A program detection method, system and electronic device
Through the static analysis method based on Rust MIR, the source code is parsed to generate intermediate intermediate representations, and the control flow diagram is constructed and fixed point iterative analysis is carried out, which solves the problem of low detection efficiency and high false alarm rate in the existing technology, and achieves efficient and accurate safety detection.
Patent Information
- Application Number
- CN202510443161.6
- Authority / Receiving Office
- CN · China
- Patent Type
- Patents(China)
- Current Assignee / Owner
- Filing Date
- 2025-04-09
- Publication Date
- 2025-07-25
- Estimated Expiration
- 2045-04-09
AI Technical Summary
The existing software error detection methods are inefficient and have high false alarm rates, making it difficult to meet the detection requirements of Rust programs.
Based on Rust MIR, static analysis is carried out, the source code is parsed by the package manager to generate intermediate intermediate representations, a control flow diagram is constructed, fixed point iterative analysis is performed, and memory security, concurrent security and numerical security detection is carried out in combination with vulnerability detectors.
It improves the detection efficiency and accuracy of the Rust program, reduces the false alarm rate, can deeply explore the semantic characteristics of the Rust program, and provides high-precision security detection results.
Smart Images

Figure CN119960764B_ABST
Abstract
Description
Technical Field
[0001] The present invention relates to the field of computer technology, and in particular, to a program detection method, system, and electronic device. Background Art
[0002] With the continuous increase in software complexity, ensuring software quality and security has become increasingly crucial. Existing software error detection methods mainly include manual code review, unit testing, and various static analysis techniques (such as pattern matching, program inconsistency detection, data flow analysis, symbolic execution, etc.).
[0003] However, manual review and unit testing are inefficient and have poor scalability when dealing with large-scale complex code; although traditional static analysis techniques can detect errors without running the program, due to the complexity of program semantics, they often face problems such as insufficient program detection accuracy, high false alarm rate, and poor support for specific programming language features, making it difficult to meet the current software program detection requirements. Summary of the Invention
[0004] Embodiments of the present invention provide a program detection method, system, and electronic device, which can solve the problems that the existing error detection technology has low detection efficiency, high false alarm rate, and is difficult to meet the detection requirements of Rust programs.
[0005] On the one hand, embodiments of the present invention disclose a program detection method, the method comprising:
[0006] Parsing the source code of a target program based on a package manager to determine an intermediate intermediate representation corresponding to the source code;
[0007] Analyzing the intermediate intermediate representation to construct a control flow graph; the control flow graph is used to reflect the execution path and state changes of the target program;
[0008] Performing fixed-point iteration analysis on the target program based on the control flow graph to determine state data corresponding to each function in the target program, and integrating the state data into global data;
[0009] Performing at least one of memory safety detection, concurrency safety detection, and numerical safety detection on the global data, and generating a detection result.
[0010] On the other hand, embodiments of the present invention disclose a program detection system, the program detection system comprising a package manager, a static analyzer, and a vulnerability detector;
[0011] The package manager is used to parse the source code of a target program to determine an intermediate intermediate representation corresponding to the source code;
[0012] The static analyzer is used to analyze the intermediate intermediate representation and construct a control flow graph; perform fixed-point iterative analysis on the target program based on the control flow graph, determine the state data corresponding to each function in the target program, and integrate the state data into global data;
[0013] The vulnerability detector is used to perform at least one of memory safety detection, concurrency safety detection and numerical safety detection on the global data and generate a detection result.
[0014] On the other hand, an embodiment of the present invention further discloses an electronic device, which includes a memory and one or more programs, wherein the one or more programs are stored in the memory and are configured to be executed by one or more processors to perform the aforementioned program detection method.
[0015] The embodiment of the present invention further discloses a readable storage medium. When instructions in the storage medium are executed by a processor of an electronic device, the electronic device can execute the aforementioned program detection method.
[0016] The embodiment of the present invention includes the following advantages: static analysis is performed with the intermediate intermediate representation (MIR) of the target program as the core. Specifically, the source code of the target program is first parsed based on the package manager to generate MIR, and the MIR is analyzed to build a control flow graph. Fixed-point iteration analysis is performed on the target program based on the control flow graph, and the type and life cycle information at the MIR level are deeply mined to determine the state data corresponding to each function in the target program, and the state data is integrated into global data; at least one of memory safety detection, concurrency safety detection and numerical safety detection is performed on the global data, and a detection result is generated. By analyzing MIR as the core, the embodiment of the present invention can deeply mine the semantic characteristics of programs such as Rust type, perform detection in multiple dimensions, and improve detection efficiency and detection accuracy. BRIEF DESCRIPTION OF THE DRAWINGS
[0017] In order to more clearly illustrate the technical solutions of the embodiments of the present invention, the drawings required for describing the embodiments of the present invention are briefly introduced below.
[0018] Figure 1 is a flowchart of a program detection method embodiment of the present invention;
[0019] Figure 2 It is a structural block diagram of a program detection system of the present invention;
[0020] Figure 3 is a structural block diagram of another program detection system of the present invention;
[0021] Figure 4It is a structural block diagram of an electronic device for program detection provided by an example of the present invention. Detailed implementation manners
[0022] Next, the technical solutions in the embodiments of the present invention will be clearly and completely described in conjunction with the accompanying drawings in the embodiments of the present invention.
[0023] Method embodiment
[0024] Referring to Figure 1 , a step flow chart of an embodiment of a program detection method of the present invention is shown. The method may specifically include the following steps:
[0025] Step 101: Parse the source code of the target program based on the package manager to determine the intermediate intermediate representation corresponding to the source code;
[0026] Step 102: Analyze the intermediate intermediate representation to construct a control flow graph; the control flow graph is used to reflect the execution path and state changes of the target program;
[0027] Step 103: Perform fixed-point iteration analysis on the target program based on the control flow graph to determine the state data corresponding to each function in the target program, and integrate the state data into global data;
[0028] Step 104: Perform at least one of memory safety detection, concurrent safety detection, and numerical safety detection on the global data, and generate a detection result.
[0029] The program detection method provided by the embodiment of the present invention can be applied to a program detection system. Referring to Figure 2 , a structural block diagram of a program detection system provided by the embodiment of the present invention is shown. As Figure 2 shown, the program detection system in the embodiment of the present invention includes a package manager, a static analyzer, and a vulnerability detector.
[0030] Among them, the package manager is used to parse the source code of the target program to generate an intermediate intermediate representation (Mid-level Intermediate Representation, MIR). MIR is a key intermediate stage before Rust code is converted into low-level intermediate representation (LLVM IR) or machine code. Rust MIR (intermediate intermediate representation) can simplify the syntax, retain key information (types and debugging data), and provide a rich and accurate basis for static analysis. The embodiment of the present invention abandons the method of relying on existing tools to analyze LLVM bitcode or custom intermediate representation, and constructs a static analysis framework based on Rust MIR, which can effectively improve the accuracy and efficiency of error detection and reduce the possibility of false positives.
[0031] It should be noted that the package manager in the embodiments of the present invention can be generated based on the package manager and build tool of Rust, and can receive user commands. By parsing the user commands, it can generate a project structure that conforms to the Rust standard for the project specified by the user, including a source code directory, configuration files, etc.
[0032] Exemplarily, in the embodiments of the present invention, the package manager can obtain the source code path of the target program to be detected and the options specified by the user according to the command-line parameters input by the user. Among them, the source code path can be the root directory of the Rust project or the path of a specific compilation unit (crate), and the source code path is used to locate and load the source code of the Rust project. The package manager calls the compiler to perform lexical analysis and syntax analysis on the source code of the target program according to the source code path and the options specified by the user, generates an abstract syntax tree (AST), and further converts the abstract syntax tree into a high-level intermediate representation (HIR). Compared with the abstract syntax tree, the high-level intermediate representation is more simplified, removing details such as macro expansion and syntax transformation, and performing preliminary type inference. In the HIR stage, the compiler performs a complete type check and completes syntax transformation. For example, it converts a for loop into a loop structure. After the type check is completed, the compiler converts the HIR into MIR. MIR can simplify complex Rust features such as ownership, lifetime, pattern matching, etc., for more efficient analysis and optimization.
[0033] Package management can identify the top-level crate to be analyzed by parsing the command-line parameters input by the user, and set environment variables, such as CHECKER_ARGS and CHECKER_TOP_CRATE_NAME. Among them, CHECKER_ARGS is used to pass the analysis options specified by the user, and CHECKER_TOP_CRATE_NAME is used to specify the name of the top-level crate. The package manager can also set necessary compilation flags, such as -Zalways_encode_mir, to ensure that complete MIR code is generated during the build process, including the MIR code of project dependencies and the standard library. In subsequent analysis steps, the package manager can pass the analysis options and the top-level crate name to the static analyzer through the environment variables and compilation flags, so that the static analyzer can comprehensively analyze the top-level crate and its dependencies based on the MIR code.
[0034] The static analyzer is used to analyze the intermediate intermediate representation, construct a control flow graph (Control Flow Graph, CFG), and perform fixed-point iteration analysis on the target program based on the control flow graph to determine the state data corresponding to each function in the target program. Among them, the control flow graph is used to reflect the execution path and state change of the target program.
[0035] It should be noted that in the embodiments of the present invention, the compilation process of the Rust compiler can be extended to embed the static analyzer into the MIR processing stage. For example, modify the rustc source code or use a compiler plugin (Nightly feature) to embed the analysis logic of the static analyzer into the compilation process.
[0036] The static analyzer operates based on the structure of MIR. Specifically, the static analyzer can decompose the source code of the target program into basic blocks, generate a control flow graph according to the control flow relationship between the basic blocks, and record information such as data flow and variable scopes.
[0037] Among them, a basic block is a code segment composed of a group of continuously executed statements, with a unique entry point and exit point, and there are no branch or jump instructions inside. Through this division, the execution path of the program is decomposed into a series of relatively independent parts, providing a good basis for subsequent analysis of control flow transfer and program state. In the control flow graph, the basic blocks are represented as nodes, and the control flow relationship between the basic blocks is described by directed edges. This graph structure can not only accurately reflect the execution path of the program, but also retain sufficient structural information, providing a reliable basis for data flow analysis, abstract interpretation, and vulnerability detection.
[0038] After completing the construction of the control flow graph, the static analyzer can analyze the state data of each function in the target program through fixed-point iteration techniques. Specifically, based on the control flow graph, guide the fixed-point algorithm to fully cover the program behavior of the target program, ensure that all possible execution paths are considered, and continuously update the state data of each function during the analysis until a certain stable state, that is, the "fixed point" is reached. Among them, the state data may include numerical information (such as value ranges or linear constraints) corresponding to variables and symbolic information (such as operations related to ownership transfer such as pointers, references, paths, etc.).
[0039] Fixed-point iteration analysis can effectively improve the accuracy and efficiency of analysis, providing a solid foundation for program security and performance optimization. The state data obtained from the iterative analysis is saved in the global data for further detection.
[0040] The vulnerability detector performs at least one of memory safety detection, concurrent safety detection, and numerical safety detection on the global data and generates a detection result.
[0041] Among them, memory safety detection is mainly used to track the ownership transfer and insecure calls of memory blocks, and accurately locate the risks of lifecycle destruction. Concurrent safety detection is used to analyze resource competition or lock order conflicts between threads, and identify the critical paths that may lead to concurrent conflicts. Numerical safety detection is used to determine the ranges of integer variables and possible arithmetic overflows in the target program, and timely capture the root causes of potential overflows and numerical overflows.
[0042] Exemplarily, when performing memory safety detection, the vulnerability detector can identify possible memory access paths in the target program through path analysis, and track the sources and destinations of pointers and references in the target program based on the memory access paths, so as to identify potential problems such as memory leaks, dangling pointers, and out-of-bounds accesses. Specifically, path analysis maintains the state information on the program execution path, including variable values, memory allocations, and constraint conditions. Among them, the path condition is a key component in path analysis, which consists of a series of branch conditions and is used to represent the execution conditions of the program on a specific path. During the path analysis process, the path condition can be dynamically updated to more accurately infer the value ranges of variables and reduce false alarms.
[0043] When performing concurrent safety detection, the vulnerability detector can extract all lock-related operations from the target program. For example, the lock acquisition operation acquire and the unlock operation unlock. Then, analyze the usage of locks by each thread to determine whether there is a deadlock risk and whether there is resource competition between multiple threads. Exemplarily, control flow analysis and lock relationship modeling can be used to construct a concurrent control flow graph to visually present resource competition or lock order conflicts between threads, and cooperate with model checking techniques to identify the critical paths that may lead to concurrent conflicts.
[0044] When performing numerical safety detection, the vulnerability detector can analyze the changes in the value ranges of variables and arithmetic conditions in the target program to determine whether there are potential numerical violations, such as out-of-bounds access or arithmetic exceptions, and timely capture the root causes of potential overflows and array out-of-bounds.
[0045] Finally, based on the analysis conclusions of memory safety detection, concurrent safety detection, and numerical safety detection, the vulnerability detector generates a detection result, makes a rich and detailed diagnostic report on all potential security violations, helps developers comprehensively master and timely fix error hazards, and ensures the safe and stable operation of the program.
[0046] The program detection method provided by the embodiment of the present invention takes Rust MIR as the core and designs a high-precision static analysis architecture. Specifically, the source code of the target program is first parsed based on the package manager to generate MIR. Then, the MIR is analyzed by the static analyzer to construct a control flow graph, and the target program is analyzed at a fixed point based on the control flow graph. The type and life cycle information at the MIR level are deeply mined to determine the state data corresponding to each function in the target program, and the state data is integrated into global data; finally, the vulnerability detector is used to perform at least one of memory safety detection, concurrency safety detection and numerical safety detection on the global data, and a detection result is generated. The embodiment of the present invention provides a program detection system specially adapted to Rust programs, which can deeply mine the semantic characteristics of Rust programs, which is conducive to improving the detection efficiency of Rust programs, reducing false alarm rates, and improving detection accuracy.
[0047] In an optional embodiment of the present invention, the step 101 of parsing the source code of the target program based on the package manager to determine the intermediate intermediate representation corresponding to the source code includes:
[0048] Step S11, analyzing the command line parameters input by the user, determining the analysis options and source code path specified by the user, and loading them into the package manager; wherein the analysis options include analyzer configuration parameters;
[0049] Step S12: the package manager identifies the analysis options according to the analysis options and sets environment variables and compilation flags; wherein the environment variables are used to transmit the analysis options specified by the user and indicate the top-level compilation unit to be analyzed; the compilation flag is used to instruct the compiler in the package manager to generate a complete intermediate intermediate representation;
[0050] Step S13: The package manager locates the source code of the target program according to the source code path, and generates an intermediate intermediate representation corresponding to the target program.
[0051] In an embodiment of the present invention, the analysis options and source code path specified by the user can be obtained from the command line arguments, and the analysis options and source code path are loaded into the package manager. Among them, the command line arguments refer to the parameters input by the user through the command line when running the program, and these parameters are used to specify the behavior of the program or the input files. The analysis options include analyzer configuration parameters and compilation flags. The analyzer configuration parameters are used to configure the static analyzer, and these parameters are responsible for integrating with the Cargo toolchain to ensure that the static analyzer is correctly called during the build process of the Rust project. The compilation flags are used to force the Rust compiler to generate and retain the complete MIR code, including the MIR of the current project, dependencies, and standard library. For example, by setting compilation flags such as -Zalways_encode_mir, it can be ensured that the static analyzer can access all necessary intermediate representation data, thereby supporting comprehensive code checking or optimization.
[0052] The source code path is the source code path of the Rust project specified by the user, usually the root directory of the project or the path of a specific coding unit. The source code path is used to locate and analyze the source code of the Rust project in subsequent steps. Exemplarily, the package manager can locate the source code of the target program according to the source code path and generate the intermediate intermediate representation corresponding to the target program.
[0053] In addition, in an embodiment of the present invention, the package manager is used to identify the top-level compilation units to be analyzed based on the analysis options, and set environment variables and compilation flags respectively.
[0054] It should be noted that the top-level compilation unit in an embodiment of the present invention refers to the main compilation unit (crate) to be analyzed specified by the user. In Rust, a crate is a compilation unit, which can be a library or an executable file. A Rust project usually consists of one or more crates.
[0055] The environment variable is a variable at the operating system level that can affect the behavior of the program when the program is running. In an embodiment of the present invention, by setting the environment variable, the analysis options specified by the user and the top-level compilation unit to be analyzed are passed to the static analyzer, and the static analyzer performs a comprehensive analysis on the top-level crate and its dependencies based on the MIR code. Exemplarily, the set environment variables can include CHECKER_ARGS and CHECKER_TOP_CRATE_NAME. Among them, CHECKER_ARGS is used to pass the analysis options specified by the user, and CHECKER_TOP_CRATE_NAME is used to specify the name of the top-level crate, that is, the analyzer configuration parameters, compilation flags, and the name of the top-level crate are passed to the static analyzer in the form of static variables respectively.
[0056] Optionally, before the step of analyzing the intermediate intermediate representation by using the static analyzer and constructing a control flow graph in step 102, the method further includes:
[0057] Step S21: Construct a global context according to the analysis option; the global context is used to provide a basic environment required for analyzing the target program;
[0058] Step S22: Initialize the static analyzer according to the global context to analyze the intermediate intermediate representation.
[0059] In an embodiment of the present invention, after completing the command line parsing of the user, the static analyzer can also be initialized. Specifically, first construct a global context according to the analysis option specified by the user, and then, based on the callback mechanism, initialize the static analyzer by using the global context.
[0060] It should be noted that the global context (GlobalContext) is an overall collection of environments containing all the information required for comprehensive analysis. The global context is like a large warehouse that stores various key "tools" and "materials" used in the program analysis. It is the basic environment for the entire analysis process to proceed smoothly and provides necessary data support for subsequent analysis operations.
[0061] Exemplarily, the global context in an embodiment of the present invention may include the type context (TyCtxt) of the compiler, session information (Session), identification information of the entry function (such as DefId), and various cache structures (such as WtoCache and function_name_cache), etc.
[0062] Among them, the type context of the compiler is used to manage the data types of each variable, function, and other elements in the target program. When the compiler processes the code, it needs to clarify the data types of each variable, function, and other elements. TyCtxt is the part used to record and manage this type-related information. For example, when the compiler encounters a variable declaration, it determines the type of this variable based on TyCtxt, such as integer type, character type, or a custom structure type, etc. This is very crucial for ensuring the type correctness and consistency during the compilation process of the code.
[0063] Session information contains some specific status and configuration data during the entire compilation session. For example, target platform information (whether to compile an executable file for the Windows system or the Linux system, etc.), specific compilation features that are enabled or disabled (such as whether optimization is enabled, whether certain specific language extensions are supported, etc.). Session information is like a "task list" for a compilation task, recording the goals to be achieved in this compilation and some special requirements.
[0064] The entry function refers to a specific function that is executed first when the program runs. The identification information of the entry function refers to the unique identifier of the entry function in the entire program definition space. Through this identification information, the compiler and analysis tools can accurately locate the definition location of the entry function, understand its parameter list, return value type and other detailed information, and then, starting from this, analyze and trace the execution flow of the entire program.
[0065] The role of the cache structure is to improve the analysis efficiency. Taking the WtoCache cache library as an example, it can cache some results obtained through complex calculations, such as the call graph of a certain function or the intermediate results of a specific type conversion, etc. When these information are needed again for subsequent analysis, they can be directly obtained from WtoCache without having to recalculate, which greatly saves time. The function_name_cache can be used to cache function names and their related meta-information. When it is necessary to quickly find the detailed information corresponding to a certain function name, it can be quickly obtained from the function_name_cache, avoiding cumbersome search operations in the entire code library.
[0066] In the embodiments of the present invention, the static analyzer can be initialized according to the global context through a callback mechanism. Exemplarily, after the command parsing is completed, the static analyzer can be initialized through the callback interface rust_driver::Callbacks. This callback interface is deeply integrated with the rustc driver program, allowing custom code (such as static analysis, code transformation, information collection, etc.) to be executed at key points during the compilation process. After the initialization is completed based on the global context, the static analyzer will be instantiated and run.
[0067] It should be noted that the callback interface in the embodiments of the present invention depends on the interface exposed by the rustc compiler. Through the callback interface, the program can execute custom code at key points. For example, through the callback interface rust_driver::Callbacks, the program can jump to execute custom code at the following four stages: (1) the command parsing stage before creating the compiler instance; (2) after parsing the entry file of the source code; (3) after macro expansion; (4) the analysis stage, that is, after type checking, borrowing checking, MIR generation, etc. In the embodiments of the present invention, the callback mechanism is mainly used at two key points. One is the command parsing stage before creating the compiler instance. Through the callback interface, the code for parsing commands and setting the running environment is transferred and executed from the compilation process. The other is the analysis stage, that is, after type checking, borrowing checking, MIR generation, etc., the MIR is analyzed by the static analyzer. Exemplarily, when an execution command is input to the compiler, the compiler enters stage (1) through the callback interface to perform command parsing. After parsing, it returns to the compiler, and the compiler continues with the compilation work. After type checking, borrowing checking, MIR generation, etc. are completed, the static analyzer is initialized through the callback interface, and the analysis stage of the static analyzer is entered to start the analysis.
[0068] In an alternative embodiment of the present invention, the analysis of the intermediate intermediate representation in step 102 to construct a control flow graph includes:
[0069] Step S31: Divide the source code into at least one basic block according to the intermediate intermediate representation, and respectively determine the control flow relationships between the basic blocks;
[0070] Step S32: Using the basic blocks as nodes, draw directed edges corresponding to the nodes according to the control flow relationships to obtain the control flow graph.
[0071] In static program analysis, the program can be divided into basic blocks to represent the execution path and state changes of the program, and a control flow graph CFG can be constructed according to the control flow relationships between the basic blocks. Exemplarily, each basic block can be used as a node in the control flow graph, and the control transfer relationships between the basic blocks (such as jump instructions, etc.) can be used as the edges of the control flow graph. For example, for a simple program code containing conditional judgment statements and loop statements, by analyzing the execution flow of the code, it is determined which basic blocks have jump relationships, thereby constructing a complete control flow graph.
[0072] Among them, a basic block is a code segment composed of a group of continuously executed statements, having a unique entry point and exit point, and there are no branch or jump instructions inside. Through this division, the execution path of the program is decomposed into a series of relatively independent parts, providing a good foundation for subsequent analysis of control flow transfer and program state.
[0073] In a control flow graph, basic blocks are represented as nodes, and the control flow relationships between basic blocks are described by directed edges. This graph structure can not only accurately reflect the execution path of a program, but also retain sufficient structural information, providing a reliable basis for data flow analysis, abstract interpretation, and vulnerability detection.
[0074] Optionally, the method further includes:
[0075] Step S33: When there is a loop structure in the control flow graph, identify the target connected component in the control flow graph;
[0076] Step S34: Based on the target connected component, decompose the control flow graph into at least one set of components;
[0077] Step S35: Starting from the first component, traverse the control flow graph based on the depth-first search algorithm and update the corresponding sorting information according to a preset sorting strategy;
[0078] Step S36: Generate a sorting result corresponding to the at least one component according to the updated sorting information.
[0079] Wherein, the component includes a single basic block or a loop structure composed of at least one basic block. The sorting result is used to indicate the analysis order corresponding to the at least one component during the fixed-point algorithm analysis of the target program.
[0080] In an embodiment of the present invention, on the basis of constructing a control flow graph, the Weak Topological Order (WTO) algorithm can be used to further optimize the static analysis process.
[0081] It should be noted that traditional topological sorting requires the graph to be acyclic, while the loop structure in the program makes the control flow graph no longer acyclic. In the embodiments of the present invention, if there is a loop structure in the control flow graph, the weak topological sorting algorithm can be used to identify the target connected components in the control flow graph, and the control flow graph can be decomposed into at least one set of components based on the target connected components. Among them, the target connected components in the embodiments of the present invention refer to the strongly connected components in the control flow graph. A component can be a single basic block or a loop structure composed of multiple basic blocks. It can be understood that if every vertex of a graph can be reached from any other point in the graph, the graph is called strongly connected. The part that can achieve strong connectivity in any directed graph is called its strongly connected component. For example, a>b, b->a, this part is the strongly connected component in this graph. In the embodiments of the present invention, the loop structure in the control flow graph can be identified through strongly connected components. Exemplarily, the loop in the control flow graph, that is, the strongly connected component, can be detected by performing a depth-first search on the control flow graph. When performing a depth-first search on the control flow graph, the paths in the graph can be explored recursively, and the access status of vertices can be traced; when a vertex that has been visited is encountered during the search, it can be determined whether there is a loop by analyzing the relationship between the access status and the current search path.
[0082] When decomposing the control flow graph, the basic blocks included in the loop structure corresponding to the strongly connected component are divided into the same component.
[0083] After decomposing the control flow graph, the sorting of each component starts. Specifically, starting from the first component, each component in the control flow graph is traversed in turn based on the Depth - First Search (DFS) algorithm, and the sorting information of each component is updated according to the preset sorting strategy. After completing the traversal of the control flow graph, the final sorting information of each component, that is, the sorting result corresponding to each component, can be obtained. When performing fixed-point iterative analysis on the target program subsequently, the analysis order corresponding to each component can be determined according to this sorting result, so as to provide a clear analysis path for static analysis. The loop structure and the dependencies between the loop and the non-loop parts can be reasonably processed, avoiding repeated and ineffective calculations of the loop structure during the analysis process, and improving the analysis efficiency. When processing the control flow graph of the program (where the basic blocks can be regarded as the nodes of the graph), the depth-first search can visit each basic block in a specific order. When sorting the basic blocks with loops, the depth-first search can help the algorithm explore deeply along the paths of the control flow graph, so as to understand the connection relationships between each basic block and provide a basis for subsequent sorting.
[0084] The preset sorting strategy in the embodiments of the present invention can select corresponding strategies according to actual analysis requirements. Exemplarily, an update strategy based on the max operation can be used as the preset sorting strategy in the embodiments of the present invention. The update strategy based on the max operation generally refers to comparing the values of different data and selecting the maximum value to update specific variables or data structures during a certain calculation or processing. In the embodiments of the present invention, when sorting each component, some attribute values related to the component may be involved, such as execution frequency, a certain quantitative index of the dependency relationship, etc. The sorting information of the component can be determined by selecting the maximum value according to these attribute values.
[0085] As an example, in the embodiments of the present invention, some initial attributes can be set for each component first, such as assigning a unique identifier to each component and initializing some variables for recording sorting information. At the same time, a stack data structure can be initialized for the depth-first search process.
[0086] Then, starting from the entry component, the control flow graph is traversed using the depth-first search algorithm. During the traversal, each accessed component is marked as visited. When encountering a component containing a loop structure, the depth-first search will go deep along the loop path until all basic blocks within the loop are traversed. For example, if there is a while loop, it will first enter the first basic block of the loop body, and then continue to go deep into other basic blocks inside the loop body according to the control flow.
[0087] During the depth-first search process, whenever a new component is accessed, the relevant sorting information can be updated according to the update strategy based on the max operation. For example, if an attribute related to the execution frequency of the component is defined, when a new component is accessed, perform a max operation on its execution frequency and the execution frequencies of the already accessed components. If the execution frequency of the new component is higher, update the sorting-related data structure to reflect the position information of this new "highest frequency" component.
[0088] When the depth-first search completes the traversal of the entire control flow graph, the final sorting result of each component is generated according to the updated sorting information. This sorting result takes into account the loop structure and some priority factors determined based on the max operation, making the arrangement of components more conducive to subsequent program analysis or optimization operations. For example, in some optimization scenarios, placing components with high execution frequencies in more forward positions helps improve the overall execution efficiency.
[0089] In an alternative embodiment of the present invention, step 103 of determining the state data corresponding to each function in the target program and integrating the state data into global data includes:
[0090] Step S41: Extract the instructions in each basic block corresponding to the target program based on the control flow graph;
[0091] Step S42: Determine whether the basic block contains only numerical operations according to the instructions in the basic block;
[0092] Step S43: When the basic block contains only numerical operations, update the numerical domain according to the value ranges and inequality relationships of the variables in the basic block;
[0093] Step S44: Otherwise, update the symbolic domain and map the constraint conditions corresponding to the symbolic information in the symbolic domain to the numerical domain.
[0094] Among them, the numerical domain is used to record the numerical information of the variables in the target program. The symbolic domain is used to manage the symbolic information in the target program.
[0095] After the CFG and WTO are constructed, the static analyzer can update the state data of each function in the target program through fixed-point iteration analysis. Among them, the state data may include numerical information (such as value ranges or linear constraints) corresponding to variables and symbolic information (such as operations related to ownership transfer such as pointers, references, paths, etc.).
[0096] Specifically, during the fixed-point iteration analysis of each basic block in the target program, the abstract domain is repeatedly updated until a certain stable state, that is, a "fixed point", is reached, so that the static analyzer continuously reduces the operation space where errors may occur, and the probability of detecting potential defects such as overflows and out-of-bounds is higher. In the embodiments of the present invention, the abstract domain in the static analyzer consists of two key sub-domains: the numerical domain and the symbolic domain.
[0097] Among them, the numerical domain is used to maintain numerical information (such as intervals or linear constraints). The numerical domain infers possible numerical overflow, out-of-bounds and other risks by continuously collecting and updating the upper and lower bounds and inequality relationships of variables during the abstract interpretation process.
[0098] The symbolic domain is used to manage symbolic information such as pointers, references, paths, etc. Among them, the mapping between the path (Path) and the symbolic value (Symbolic Value) can accurately record operations such as pointer aliasing, memory allocation and ownership transfer in the program.
[0099] When dealing with pure numerical operations, the static analyzer mainly updates the numerical domain. For example, update the numerical domain according to the value ranges and inequality relationships of the variables in the basic block.
[0100] When there is at least one of pointers, references, and function calls in a basic block, the static analyzer updates the symbol information in the symbol domain, maintains address or alias information, and maps index or address-related constraints (such as idx < arr.len() in "arr[idx]") to the numeric domain when necessary, thus establishing a "deep integration" between symbolic analysis and numeric analysis.
[0101] As an example, assume that the target program contains 4 basic blocks. Among them, basic block 1 contains pointer movement, basic block 2 contains array access, basic block 3 contains numeric operations, and basic block 4 contains pointer aliasing. The initial state of the numeric domain is "idx [0, len(arr)-1], ptr [0, sys.maxsize] (the initial value range of variable idx is from 0 to len(arr)-1, and the initial value range of variable ptr is from 0 to sys.maxsize)", and the initial state of the symbol domain is "ptr → arr[0] (assuming it initially points to the first element)". After static analysis, the state update process of the numeric domain and the symbol domain is as follows:
[0102] # Basic block 1: Pointer movement
[0103] ptr += idx # Symbol domain update: ptr → arr[idx]
[0104] # Numeric domain update: ptr [0 + 0, sys.maxsize + (len(arr)-1)]
[0105] # Basic block 2: Array access
[0106] value = arr[ptr] # Trigger index constraint check
[0107] # Numeric domain constraint: ptr < len(arr) → must satisfy 0 ≤ ptr < len(arr)
[0108] # If len(arr) = 10, the current range of ptr is [0, 9] (legal) or [5, 14] (out of bounds)
[0109] # Basic block 3: Numeric operations
[0110] value = 2 # Numeric domain update: value [0 2, max(arr) 2]
[0111] # Basic Block 4: Pointer Aliasing
[0112] alias_ptr = ptr # Symbolic domain records the aliasing relationship: alias_ptr ptr
[0113] # Subsequent operations on alias_ptr will synchronously update the symbolic information of ptr
[0114] In the above example, after calculation:
[0115] The value range of variable ptr in the numerical domain is updated to: ptr [0, sys.maxsize + (len(arr)-1)], and the corresponding constraint check is: ptr < len(arr) (array out-of-bounds detection).
[0116] The pointer mapping of the record in the symbolic domain is: ptr → arr[idx], and the aliasing relationship is: alias_ptr ptr, and the path record is: The path of ptr is dynamically updated as idx changes.
[0117] The corresponding index or address constraints are: 1) arr[ptr] triggers the constraint: ptr < len(arr); 2) Constraint propagation: Associates the symbolic ptr with the numerical len(arr); 3) Cross-domain fusion: When the numerical domain interval of ptr exceeds len(arr), an out-of-bounds alarm is triggered.
[0118] Assume len(arr) = 10, idx = 5, ptr = 0, the static analysis process is: Numerical domain update: ptr [0+5,...] → [5,...], Symbolic domain update: ptr → arr[5], Index constraint check: 5 < 10 → Legal.
[0119] If idx is subsequently assigned the value 15 (through another path), the analysis process is: Numerical domain detection: idx [15,15], Symbolic domain update: ptr → arr
[15] , Index constraint check: 15 < 10 → Out-of-bounds alarm.
[0120] Optionally, the method further includes:
[0121] Step S45, when performing fixed-point iteration analysis on the loop structure in the target program, if the iteration count of at least one first variable in the loop structure is greater than a preset threshold, then expand the value range corresponding to the first variable to the global top element;
[0122] Step S46: After the first variable reaches an initial fixed point, perform a narrowing operation on the value range of the first variable according to the value corresponding to the fixed point.
[0123] When performing fixed-point iteration analysis on a loop structure, the static analyzer will, according to the sorting result determined by weak topological sorting in the foregoing steps S33 to S36, first analyze the basic blocks before the loop structure and then enter the analysis of the loop structure. Inside the loop structure, multiple iterations of analysis may be required until the variable states within the loop structure reach a stable state.
[0124] It can be understood that direct iterative calculation often faces the problem that the value range of the abstract domain may be very large or even infinite, resulting in difficulty for the iterative process to converge within a finite time. In the embodiments of the present invention, widening and narrowing strategies can be adopted to optimize the fixed-point iteration analysis process of the loop structure.
[0125] Specifically, when the fixed point has not been reached after multiple iterations in the loop structure, for example, the number of iterations of at least one first variable in the loop structure is greater than a preset threshold, the static analyzer will trigger a widening operation on the first variable when the number of iterations exceeds the preset threshold to avoid infinite iterations. Exemplarily, if some variables in the numerical domain continue to expand after multiple iterations, the static analyzer will expand the value range of the variable to the global top element at once, that is, expand the value range to the maximum value range allowed by the target program, for example, directly jump from [-3, 20] to [-∞, +∞], so as to ensure convergence in a finite number of steps.
[0126] The widening operation may result in loss of precision, but it can be partially recovered in the subsequent local narrowing process. At the same time, the mapping information of the symbolic domain regarding pointers and addresses will not be completely discarded with the widening of the numerical domain to reduce false negatives.
[0127] It should be noted that the widening operation may also result in loss of precision of the analysis result. To compensate for the possible loss of precision caused by the widening operation, the embodiments of the present invention perform a narrowing operation on the first variable after the widening operation. Specifically, after the first variable reaches an initial fixed point, perform a narrowing operation on the value range of the first variable according to the value corresponding to the fixed point, so that the overly broad value interval "shrinks" downward.
[0128] The narrowing operation can introduce a "backtracking" operation during the iteration process to gradually approach a more accurate fixed point and "refine" the analysis result. Specifically, in each iteration, the narrowing operator compares the current iteration result with the previous iteration result. If it is found that the iteration result can still "move" downward along the lattice structure, the narrowing operator will "narrow" the current result to a lower abstract state. For example, when it is detected in the downstream branch that the first parameter x ≥ 0, the previously over-widened x can be retracted from [-∞, +∞] to [0, +∞]. This backward refinement can recover a certain analysis accuracy while ensuring convergence.
[0129] By combining the widening and narrowing strategies, the embodiments of the present invention improve the applicability of the fixed point iteration technique in program analysis, can achieve a balance between efficiency and accuracy, and can quickly expand the coverage range and ensure the final accuracy recovery in scenarios of loops or depth searches.
[0130] As an example, when dealing with a loop structure in the embodiments of the present invention, the steps of performing widening and narrowing operations on the established relevant parameters are as follows:
[0131] / / / When the number of iterations exceeds the threshold, use the widening operator to accelerate convergence
[0132] fn extrapolate(
[0133] &mut self,
[0134] circle: &WtoCircle, / / Represents a loop structure (strongly connected component)
[0135] before: AbstractDomain <domaintype>,
[0136] after: AbstractDomain <domaintype>,
[0137] ) ->AbstractDomain <domaintype>{
[0138] let iteration = circle.get_iter_num();
[0139] let widening_delay = self.context.analysis_options.widening_delay;
[0140] / / If the number of iterations has not exceeded the threshold, only perform ordinary union operations; otherwise, execute widen.
[0141] if iteration <= widening_delay {
[0142] before.join(&after)
[0143] } else {
[0144] before.widening_with(&after) / / Widening operator
[0145] }
[0146] }
[0147] / / / After the initial widening is completed, several rounds of narrowing operations can be performed to further approximate the true state
[0148] fn refine(
[0149] &mut self,
[0150] circle: &WtoCircle,
[0151] before: AbstractDomain <domaintype>,
[0152] after: AbstractDomain <domaintype>,
[0153] ) ->AbstractDomain <domaintype>{
[0154] let iteration = circle.get_iter_num();
[0155] / / The first narrowing usually uses meet()
[0156] if iteration == 1 {
[0157] before.meet(&after)
[0158] } else {
[0159] before.narrowing_with(&after) / / Other rounds can call the narrower operator
[0160] }
[0161] }
[0162] In the embodiments of the present invention, by combining widening and narrowing strategies during the fixed-point iteration analysis of loop structures, the accuracy and efficiency of the analysis can be improved, providing a basis for the security and performance optimization of programs.
[0163] Referring to Figure 3 , a structural block diagram of another program detection system provided by the embodiments of the present invention is shown. As Figure 3 shown, in an optional embodiment of the present invention, according to the detection content, the vulnerability detector can be divided into a memory security detector, a concurrency security detector, and a numerical security detector, and the global data can be interacted and collaborated through accessing an abstract domain library and a solver in the vulnerability detector to obtain a detection result.
[0164] Among them, the abstract domain library is used to approximately calculate the numerical range of program variables under the abstract interpretation framework. Exemplarily, the abstract domain library in the embodiments of the present invention can be the Apron (Abstract Interpretation Library for Numerical Domains) numerical abstract domain library. The Apron numerical abstract domain library can support multiple abstract domains, such as the interval domain (Interval), the octagon domain (Octagon), the polyhedron domain (Polyhedra), the linear congruence domain (Linear Congruence), etc. Among them, the interval domain is used to track the upper and lower limits of variables, such as x ∈ [1, 10]. The octagon domain is used to describe the linear inequality relationship between variables, such as x - y ≤ 5. The polyhedron domain is used to define a complex convex polyhedron region through linear constraints. The linear congruence domain is used to analyze the modulus constraints of variables, such as x 2 mod 4.
[0165] The solver is used to determine the satisfiability of logical formulas (SAT / SMT). Exemplarily, the solver in the disclosed embodiments may include the Z3 solver, which supports multiple theories, such as arithmetic theories (linear / non-linear integer and real arithmetic), bit-vector theories (for precisely handling fixed-length bit-level operations), array theories (for analyzing read and write operations of arrays), uninterpreted functions and data types (UF+DT), etc.
[0166] Embodiments of the present invention can generate a detailed diagnostic report on all potential security violations in the target program based on the abstract domains of the abstract domain library and the constraint-solving capabilities of the solver, obtaining a detection result, thereby helping developers comprehensively grasp and timely fix error risks to ensure the secure and stable operation of the program.
[0167] Optionally, the vulnerability detector includes a memory safety detector, a concurrency safety detector, and a numerical safety detector. The at least one of memory safety detection, concurrency safety detection, and numerical safety detection of the global data in step 104 and generating a detection result includes at least one of the following:
[0168] Step S51: Use the global data to perform path analysis on the target program to identify memory access paths in the target program; perform symbolic analysis on the target program based on the memory access paths to trace the ownership transfer and insecure calls corresponding to the target program, generating a memory safety detection result;
[0169] Step S52: Analyze the lock usage in the target program and construct a lock dependency graph; based on the global data and the lock dependency graph, detect potential concurrency safety issues in the target program, generating a concurrency safety detection result;
[0170] Step S53: Use the global data to respectively determine the value ranges corresponding to each variable in the target program and construct a linear constraint system; detect potential numerical safety issues in the target program according to the linear constraint system, generating a numerical safety detection result.
[0171] Wherein, the linear constraint system is used to characterize the mutual relationship and operation conditions between variables.
[0172] In an embodiment of the present invention, a memory safety detector can be used to perform memory safety detection on a target program. Specifically, global data can be used to perform path analysis on the target program to identify memory access paths in the program; based on the memory access paths, symbolic analysis is performed on the target program to track the transfer of ownership of memory blocks and insecure calls in the target program, and a memory safety detection result is generated. The memory safety detector maintains state information on the program execution path through path analysis, including variable values, memory allocation, and constraint conditions, etc. The path condition is a key component in path analysis, which consists of a series of branch conditions and is used to represent the execution conditions of the program on a specific path. During the memory safety detection process, the memory safety detector dynamically updates the path condition and saves the updated path condition in the global data for the static analyzer to read. The static analyzer can more accurately infer the value range of variables based on the path condition, thereby reducing false alarms.
[0173] During the path analysis process, the memory safety detector maps each explicit or implicit memory allocation point, as well as all references or pointers related to the allocation, into a unified abstract semantics. When the static analyzer traverses the program control flow (i.e., CFG), once it detects behaviors such as dynamic allocation, static allocation, or stack allocation, it records under which branch conditions which abstract memory object is allocated. When a program statement passes a pointer to another function or associates it with a new variable through assignment, the path analysis synchronously updates the mapping relationship of "pointer to abstract memory object" and uses these relationships for further inference in the next symbolic execution. Here, the abstract memory object refers to the intermediate representation of memory objects such as data structures or variables stored in memory.
[0174] Furthermore, based on the path analysis, the memory safety detector performs symbolic analysis on the target program based on the memory access paths to construct the symbolic state of the target program. During the symbolic analysis process, the memory safety detector simulates the execution process of the program, tracks the transfer of ownership and insecure calls by maintaining memory and pointer reference information, and can identify potential memory safety issues that may occur under a specific path.
[0175] As an example, assume the target program is as follows:
[0176] #include<stdio.h>
[0177] #include<stdlib.h>
[0178] void func(int ptr) {
[0179] if ( ptr>10) {
[0180] ptr = 20;
[0181] }
[0182] }
[0183] int main() {
[0184] int p = (int )malloc(sizeof(int));
[0185] if (p == NULL) {
[0186] return 1;
[0187] }
[0188] p = 5;
[0189] func(p);
[0190] printf("%d\n", p);
[0191] free(p);
[0192] return 0;
[0193] }
[0194] In the embodiments of the present invention, the path analysis process of the target program in the above example is as follows:
[0195] 1. Use global data to perform path analysis on the target program and identify the memory access paths in the program. Specifically:
[0196] 1) Global data initialization: At the beginning of the analysis, the global data contains the basic information of the program, such as variable declarations, function definitions, etc. For the above code, the global data records the existence of the main function and the func function, and that p is a pointer to an int type.
[0197] 2) Path identification:
[0198] In the main function, the first statement int p = (int )malloc(sizeof(int)); is a memory allocation point that creates a new abstract memory object. This abstract memory object can be marked as heap_block_1, and a mapping relationship from p to heap_block_1 is established and recorded in the global data.
[0199] The subsequent if (p == NULL) is a branch condition and is part of the path condition. The path condition is represented by two paths: p == NULL and p != NULL. Under the path of p != NULL, the following is executed p = 5, which is a memory access operation that updates the value of heap_block_1.
[0200] When calling func(p), p is passed to the func function. Path analysis will synchronously update the "pointer-to-heap-block" mapping relationship. In the func function, ptr also points to heap_block_1.
[0201] In the func function, if ( ptr>10) is another branch condition, and the path condition is further refined into ptr>10 and ptr<= 10 two paths. Under the ptr>10 path, the following is executed ptr = 20, which updates the value of heap_block_1.
[0202] Returning to the main function, continue to execute printf("%d\n", p); is a read operation on heap_block_1. Finally, free(p); releases heap_block_1.
[0203] 2. Perform symbolic analysis on the target program based on the memory access path, trace the ownership transfer and insecure calls of memory blocks in the target program, and generate memory safety detection results. Specifically:
[0204] In the main function, p is the owner of heap_block_1. When calling func(p), ptr obtains temporary access rights to heap_block_1, but the ownership still belongs to p.
[0205] In the func function, according to if ( For the branch condition of ptr > 10, different operations are performed on the value of heap_block_1.
[0206] Throughout the process, the memory safety detector simulates the execution process of the program and maintains memory and pointer reference information.
[0207] The possible security issues of the target program in the above example are:
[0208] 1. Memory leak. If there is no corresponding free operation after memory is allocated by malloc, it will cause a memory leak. For example, if the line of code free(p); is deleted, heap_block_1 will not be released, and the program will continuously occupy this part of memory until the program ends.
[0209] 2. Dangling pointer. If a pointer is still used after the memory is released, a dangling pointer problem will occur. For example, after free(p); if printf("%d\n", p) is executed, at this time the memory pointed to by p has been released, and accessing this memory will cause undefined behavior.
[0210] 3. Out-of-bounds memory access. Although not shown in this simple example, if there is array access in the code and the accessed index exceeds the boundary of the array, an out-of-bounds memory access problem will occur. For example, if there is an array int arr
[10] and arr
[15] is accessed in the code, it will access a memory area that does not belong to this array, which may cause the program to crash or data corruption.
[0211] 4. Double free. If the same piece of memory is freed multiple times, security issues will also occur. For example, if free(p); is executed again after the release function free(p); it will cause double free, which will damage the memory management system and may cause the program to crash.
[0212] Through path analysis and symbolic analysis, the memory safety detector can identify these potential security issues and generate corresponding detection results.
[0213] The concurrent security detector is used to perform concurrent security detection on the target program. Specifically, in the embodiments of the present invention, the concurrent security detector constructs a lock dependency graph by analyzing the lock usage in the target program, and then based on the global data and the lock dependency graph, detects potential concurrent security issues in the target program and generates concurrent security detection results.
[0214] Among them, the lock dependency graph is used to track the acquisition and release relationships of locks by each thread in the target program. Through the lock dependency graph, the concurrent security detector can identify the lock acquisition order that may lead to deadlocks. Deadlock refers to an infinite waiting state that occurs when two or more threads are waiting for resources held by each other. Through lock analysis, the concurrent security detector can identify deadlocks in advance and generate corresponding alarm messages, which is conducive to developers promptly fixing problems and avoiding the occurrence of such situations.
[0215] Optionally, analyzing the lock usage in the target program and constructing a lock dependency graph includes:
[0216] Extracting lock-related operations from the target program and respectively obtaining the execution paths of each thread for the locks;
[0217] Constructing the lock dependency graph corresponding to the target program according to the execution paths of each thread for the locks; the lock dependency graph is used to reflect the acquisition and release order of each thread for the locks.
[0218] In the embodiment of the present invention, the concurrent security detector first identifies potential concurrent problems by analyzing the lock usage in the program. The concurrent security detector will collect and analyze the acquisition and release order of locks and construct a lock dependency graph.
[0219] Specifically, the concurrent security detector can extract all lock-related operations from the target program, such as acquire and unlock, and construct a lock dependency graph based on the execution path of each thread to track the acquisition and release relationships of the locks. For example, when it is detected that a certain thread executes acquire_lock(A) and then acquire_lock(B), a directed edge from A to B is added in the lock dependency graph, indicating that the current thread is holding A while requesting B. If unlock(A) appears at a subsequent position, it means that the thread has released lock A; at this time, the dependency information related to A needs to be removed from the dependency graph, or the node A is marked as "released", and the specific implementation can be determined according to the requirements of the analyzer. When there is a lock acquisition order among multiple threads, that is, T1 holds A first and then holds B, and T2 holds B first and then holds A, a cyclic dependency path may be formed, indicating a potential deadlock.
[0220] The concurrent security detector can use the depth-first search algorithm in the lock dependency graph for cycle detection. Once a cycle is found in the graph, it indicates the existence of circular waiting and reports the potential deadlock risk. For mutexes and read-write locks (rwlocks), the concurrent security detector can further distinguish different holding methods of read locks and write locks, and incorporate corresponding nodes or marks in the lock dependency graph to achieve more refined conflict judgment.
[0221] In addition, based on lock analysis, the concurrent security detector can further detect potential concurrent security issues in the target program by performing condition variable analysis, atomic operation analysis, race condition detection, atomicity analysis, etc. on the target program.
[0222] As an example, assume a target program containing multiple threads is as follows:
[0223] # Define two locks
[0224] lock_A = threading.Lock()
[0225] lock_B = threading.Lock()
[0226] # Global variable to simulate shared resources
[0227] shared_variable = 0
[0228] def thread_1():
[0229] global shared_variable
[0230] lock_A.acquire()
[0231] # Simulate the operation of incrementing the variable of lock A by 1
[0232] shared_variable += 1
[0233] lock_B.acquire()
[0234] # Simulate the operation of multiplying the variable of lock B by 2
[0235] shared_variable = 2
[0236] lock_B.release()
[0237] lock_A.release()
[0238] def thread_2():
[0239] global shared_variable
[0240] lock_B.acquire()
[0241] # Simulate the operation of decrementing the variable of lock B by 1
[0242] shared_variable -= 1
[0243] lock_A.acquire()
[0244] # Simulate the operation of dividing the variable of lock A by 2
[0245] shared_variable / = 2
[0246] lock_A.release()
[0247] lock_B.release()
[0248] # Create threads
[0249] t1 = threading.Thread(target=thread_1)
[0250] t2 = threading.Thread(target=thread_2)
[0251] # Start threads
[0252] t1.start()
[0253] t2.start()
[0254] # Wait for threads to end
[0255] t1.join()
[0256] t2.join()
[0257] print(f"Final value of shared_variable: {shared_variable}")
[0258] In the embodiments of the present invention, the concurrent security detector constructs the lock dependency graph of the target program in the above example through the following steps:
[0259] 1. Extract lock operations. The lock operations in threads thread_1 and thread_2 can be extracted from the code:
[0260] thread_1:acquire_lock(A)→acquire_lock(B)→release_lock(B)→release_lock(A)
[0261] thread_2: acquire_lock(B) → acquire_lock(A) → release_lock(A) → release_lock(B)
[0262] 2. Build a lock dependency graph. Initially, the lock dependency graph is empty.
[0263] For thread_1: When acquire_lock(A) is executed and then acquire_lock(B) is executed, a directed edge from A to B is added to the lock dependency graph, indicating that thread_1 holds A while requesting B.
[0264] For thread_2: When acquire_lock(B) is executed and then acquire_lock(A) is executed, a directed edge from B to A is added to the lock dependency graph, indicating that thread_2 holds B while requesting A.
[0265] At this time, there is a loop in the lock dependency graph: A → B → A.
[0266] Next, the concurrent safety detector performs the following concurrent detection process on the target program of the above example:
[0267] 1. Based on the analysis of the access status of each variable in the global data, determine whether the same variable is accessed and modified by multiple threads. Exemplarily, the global variable shared_variable is accessed and modified by multiple threads, which may lead to a race condition. For example, thread_1 and thread_2 perform read and write operations on shared_variable simultaneously, which may result in data inconsistency.
[0268] 2. Ring detection based on the dependency graph. The concurrent safety detector uses the depth - first search algorithm to detect loops in the lock dependency graph. In the above example, a loop A → B → A is detected, indicating the existence of circular waiting.
[0269] In the target program of the above example, the situations where the concurrent safety detector may detect risks are:
[0270] 1. Deadlock risk. When there is a loop in the lock dependency graph, such as A → B → A in the above example, it means that there is circular waiting among multiple threads, which may lead to deadlock. For example, thread_1 holds A and requests B, while thread_2 holds B and requests A. If neither thread releases the held lock, they will fall into a deadlock state.
[0271] 2. Race condition risk. Since multiple threads access and modify the global variable shared_variable simultaneously, race conditions may occur. For example, if thread_1 and thread_2 perform read and write operations on shared_variable at the same time, data inconsistency may result. If thread_1 reads the value of shared_variable and then thread_2 modifies it, subsequent operations of thread_1 may use the old value, leading to incorrect results.
[0272] By analyzing the lock dependency graph and checking the access status of each variable in the global data, the concurrent security detector can detect these potential concurrent security issues.
[0273] The numerical security detector is used to perform numerical security detection on the target program. Specifically, the numerical security detector can determine the value range corresponding to each variable in the target program using the global data, construct a linear constraint system, and then detect potential numerical security issues in the target program based on the linear constraint system to generate numerical security detection results.
[0274] Among them, the linear constraint system is used to describe the mutual relationship and operation conditions between variables. Exemplarily, after obtaining the value range corresponding to each variable in the target program, the numerical security detector converts the conditions related to comparison instructions or arithmetic instructions into linear inequalities and incorporates each linear inequality into a unified constraint system. During subsequent numerical security detection, potential numerical security issues such as overflow, out-of-bounds, and division-by-zero errors in the target program can be captured in a timely manner by solving the linear constraint system to determine the range of each integer variable and possible operation out-of-bounds.
[0275] As an example, assume the target program is as follows:
[0276] def calculate(a, b):
[0277] if a>10:
[0278] c = a + b;
[0279] if b<5:
[0280] d = a - b;
[0281] result = c×d;
[0282] return result;
[0283] # Call the function
[0284] a = 15;
[0285] b = 3;
[0286] output = calculate(a, b);
[0287] print(output);
[0288] In the embodiment of the present invention, the analysis and detection process of the numerical security detector for the target program of the above example is as follows:
[0289] 1. Determine the value range of each variable according to the global data.
[0290] In this simple example, the global data can be the parameter information passed in when the function is called, as well as the constant information clearly given in the program. Among them, the global data analyzed by the data security detector can be determined according to the state data of each function. For example, the value range or linear constraint corresponding to the variable. Based on these data, the value range of each variable is determined.
[0291] For the variable a, the value passed in when the calculate function is called is 15, but from the code logic, there will be subsequent operations under the condition of if a>10, so the value range of a can be determined as a>10. For the variable b, the value passed in when called is 3, combined with the condition of if b<5, the value range of b is b<5. The variable c is calculated by a + b under the condition of a>10, so the value range of c depends on a and b. The variable d is calculated by a - b under the condition of b<5, and its value range also depends on a and b. The variable result is calculated by c × d, and its value range depends on c and d.
[0292] In summary, a>10, b<5, c and d depend on a and b, and result depends on c and d.
[0293] 2. Convert the relevant operation conditions into linear inequalities.
[0294] For if a>10, it can be directly converted into the linear inequality a - 10>0; for if b<5, it is converted into the linear inequality 5 - b>0; for c = a + b, it can be expressed as c - a - b = 0; for d = a - b, it can be expressed as d - a + b = 0.
[0295] 3. Construct a linear constraint system. Combine the above-obtained linear inequalities and equations together to construct a linear constraint system:
[0296]
[0297] 4. Detect numerical security issues such as out - of - bounds operation detection and overflow judgment based on a linear constraint system.
[0298] 1) Out - of - bounds detection. Assume considering the range of integer variables. For example, in a 32 - bit signed integer system, the range of integers is from - 2147483648 to 2147483647. For c = a + b, it is necessary to check whether c will exceed this range. According to the linear constraint system, the possible range of c can be inferred by analyzing the value ranges of a and b. Given a>10 and b<5, it can be known that c = a + b>10 + b and c = a + b<a + 5. If the values of a and b cause c to exceed the integer range, an out - of - bounds problem will be detected. For d = a - b, similarly, it can be inferred whether d will be out - of - bounds based on the value ranges of a and b.
[0299] 2) Overflow detection. For the multiplication operation result = c×d, it is necessary to check whether an overflow will occur. Specifically, it can be judged according to the value ranges of c and d in combination with the maximum representation range of integers. For example, if c and d have large values, their product may exceed the integer range and cause an overflow.
[0300] 3) Division - by - zero error detection. In this example, there is no division operation, so there is no division - by - zero error. However, if there is a division operation in the code, such as e = f / g, then it is necessary to check whether g may be 0, that is, add g!= 0 as a linear inequality to the linear constraint system for solution and judgment.
[0301] Through the solution and analysis of the linear constraint system, the numerical security detector can timely capture potential numerical security issues such as overflow, out - of - bounds, and division - by - zero errors in the target program.
[0302] Optionally, the symbolic analysis of the target program based on the memory access path described in step S51 traces the ownership transfer and insecure calls corresponding to the target program, and generates a memory security detection result, including:
[0303] Sub - step S511: Based on the memory access path, trace the source and destination of the pointers related to memory allocation in the target program, and update the mapping relationship between the pointers and memory blocks;
[0304] Sub - step S512: According to the mapping relationship, simulate the symbolic execution process in the target program, construct the symbolic state of the target program, update the abstract domain, and mark the target call operation;
[0305] Sub - step S513: In the case of detecting an insecure operation related to the target call operation, generate the detection information corresponding to the target call operation;
[0306] Sub-step S514: Trace the memory allocation and release operations in the target program according to the detection information, and detect the legality of the memory release operation.
[0307] After the memory safety detector identifies the possible memory access paths in the target program through path analysis, it can, based on the memory access paths, trace the sources and destinations of the pointers related to memory allocation in the target program, and update the mapping relationship between the pointers and the memory blocks. Specifically, path analysis maintains the state information on the program execution path, including variable values, memory allocation, and constraint conditions, etc. The path condition is a key component in path analysis, which consists of a series of branch conditions and is used to represent the execution conditions of the program on a specific path.
[0308] As an example, assume the target program is as follows:
[0309] void func(int ptr) {
[0310] int new_ptr = (int )malloc(sizeof(int));
[0311] new_ptr = 10;
[0312] ptr = new_ptr;
[0313] }
[0314] int main() {
[0315] int p = NULL;
[0316] if (rand() % 2 == 0) {
[0317] func(&p);
[0318] } else {
[0319] p = (int )malloc(sizeof(int));
[0320] p = 20;
[0321] }
[0322] if (p != NULL) {
[0323] printf("%d\n", p);
[0324] free(p);
[0325] }
[0326] return 0;
[0327] }
[0328] The process by which the memory safety detector performs path analysis on the target program of the above example to identify memory access paths, trace the sources and destinations of pointers, and update the mapping relationship between pointers and memory blocks is as follows:
[0329] 1. Identify memory access paths. In the target program of the above example, operations related to memory allocation, assignment, and release are involved. The memory safety detector needs to find the paths formed by these operations. Specifically:
[0330] In the main function, the variable p is initialized to NULL. Then, a branch condition rand() % 2 == 0 is encountered, generating two different memory access paths.
[0331] Path 1: When rand() % 2 == 0 is true, func(&p) is called. In the func function, memory is allocated, the address of the newly allocated memory block is assigned to new_ptr, and then the value of new_ptr is assigned to p.
[0332] Path 2: When rand() % 2 == 0 is false, memory is directly allocated in the main function, and the address of the newly allocated memory block is assigned to p.
[0333] After that, there is a conditional check p != NULL. If p is not NULL, the memory block pointed to by p will be accessed, and finally, the memory block will be freed.
[0334] 2. Trace the sources and destinations of pointers.
[0335] Initial state: At the beginning of the main function, the pointer p is initialized to NULL and does not point to any memory block at this time.
[0336] Tracing of Path 1: When entering the func function, new_ptr allocates a new memory block through malloc, and new_ptr points to this new memory block. Then, the statement ptr = new_ptr assigns the value of new_ptr to p, so p now points to the memory block pointed to by new_ptr.
[0337] Tracking of path 2: In the main function, malloc is directly called to allocate a memory block for p, and p points to this newly allocated memory block.
[0338] Subsequent operations: When the if (p != NULL) condition is true, access the memory block pointed to by p (through p), and finally call free(p) to release the memory block. At this time, p no longer points to a valid memory block.
[0339] 3. Update the mapping relationship between pointers and memory blocks.
[0340] Initial mapping: p is initially NULL and has no corresponding memory block mapping.
[0341] Mapping update under path 1: In the func function, new_ptr is mapped to the newly allocated memory block (assuming it is memory_block_1). After ptr = new_ptr, p is also mapped to memory_block_1.
[0342] Mapping update under path 2: After calling malloc in the main function, p is mapped to the newly allocated memory block (assumed to be memory_block_2).
[0343] After releasing the memory: When free(p) is called, the mapping relationship between p and the previously mapped memory block (memory_block_1 or memory_block_2) is released, and p becomes an invalid pointer.
[0344] Throughout the process, path conditions (such as rand() % 2 == 0 and p != NULL) determine which path the program will follow, thus affecting the mapping relationship between pointers and memory blocks. For example, the condition rand() % 2 == 0 determines whether p is allocated memory through the func function or directly in the main function. The p != NULL condition ensures that p points to a valid memory block when accessing and releasing memory.
[0345] Based on the path analysis, the memory safety detector performs symbolic analysis and simulates the symbolic execution process in the target program according to the mapping relationship between pointers and memory blocks to build the symbolic state of the target program, update the abstract domain and mark the target call operations.
[0346] The abstract domain in the embodiment of the present invention includes a symbol domain and a value domain.
[0347] Among them, the symbol domain is used to record pointers, references, or other quantities that can point to memory locations, abstractly representing the mapping of "symbol → abstract memory object", as well as alias information and possible ownership transfers during function calls. If there is an ownership takeover function like "Vec::from_raw_parts" in the target program, the memory safety detector can mark the status of the corresponding pointer in the symbol domain, indicating that it may be transferred to a container structure at a higher level of abstraction.
[0348] The numeric domain is responsible for managing numeric properties such as intervals and linear inequalities related to each variable or expression. After the symbol domain determines the abstract memory object of a pointer or an array, the numeric domain can more precisely represent the range of memory access through constraints such as "subscript < array length", thereby realizing the collaborative inference of pointer operations and numeric operations.
[0349] During the process of symbolic execution, the memory safety detector continuously updates the abstract domain: for the numeric constraint part, it infers the feasible intervals of integer variables according to the path conditions; for the symbol domain part, it performs pointer alias analysis, marks potential access permissions and lifecycle information according to the call point or assignment point. If the memory object corresponding to a pointer has been released or moved to another scope, the symbol domain will record this situation and trigger corresponding memory safety checks in subsequent steps.
[0350] The target call operation in the embodiments of the present invention refers to a dangerous interface call or function call that may cause memory safety problems, such as detecting a dangerous API call, such as a function like "from_raw_parts". The "symbol to abstract memory object" mapping maintained by the symbol domain will be further marked as a target call operation. For example, information such as "ownership transfer of this memory object" or "this call is likely to cause unsafe release" will be marked. During "taint analysis", the memory safety detector will mark such pointers or memory blocks as affected objects (i.e., "taint sources") and identify "taint propagation" during subsequent execution and parameter passing. If during an interface call or function call, the memory safety detector detects that tainted data reaches certain unsafe operations (such as "release operation" or "out-of-bounds write"), it indicates that there may be a memory safety vulnerability on this path, and corresponding detection information is generated.
[0351] As an example, assume the target program is as follows:
[0352] use std::ptr;
[0353] fn main() {
[0354] let mut arr = vec![1, 2, 3, 4, 5];
[0355] let ptr = arr.as_mut_ptr();
[0356] let len = arr.len();
[0357] let cap = arr.capacity();
[0358] / / Simulate the ownership takeover function call
[0359] let new_vec = unsafe { Vec::from_raw_parts(ptr, len, cap)};
[0360] / / Assume there are subsequent operations on new_vec
[0361] for i in 0..len {
[0362] unsafe {
[0363] new_vec.as_mut_ptr().add(i) = 2;
[0364] }
[0365] }
[0366] drop(new_vec); / / Release the memory
[0367] }
[0368] In the embodiment of the present invention, the process of the memory safety detector performing symbolic analysis on the target program of the above example and updating the abstract domain is as follows:
[0369] 1. Simulate the symbolic execution process in the target program according to the mapping relationship between the pointer and the memory block.
[0370] Initial state: At the beginning of the main function, a Vec type arr is created, which contains 5 elements. The arr.as_mut_ptr() operation assigns the pointer of arr to ptr, and at this time ptr points to the memory block managed by arr. len and cap respectively record the length and capacity of arr.
[0371] Ownership takeover function call: Call the function Vec::from_raw_parts(ptr, len, cap), which is an ownership takeover function. During symbolic execution, the memory safety detector will simulate this call and recognize that the ownership of ptr is transferred from arr to new_vec.
[0372] Subsequent operations: Enter the for loop to modify each element in new_vec. During symbolic execution, pointer arithmetic (new_vec.as_mut_ptr().add(i)) and memory access ( new_vec.as_mut_ptr().add(i) = 2) will be simulated.
[0373] Release memory: Call drop(new_vec) to release the memory block managed by new_vec. Symbolic execution will simulate this release operation and update the status of the pointer and the memory block.
[0374] 2. Construct the symbolic state of the target program.
[0375] For the symbolic domain, for the initial mapping, ptr is mapped to the abstract memory object (assumed to be memory_block_1) managed by arr. For the ownership transfer, after calling Vec::from_raw_parts(ptr, len, cap), new_vec takes over the ownership of ptr, and the symbolic domain records that new_vec is mapped to memory_block_1 while marking that the ownership of ptr has been transferred. For alias information, in the for loop, new pointers are aliased by new_vec.as_mut_ptr().add(i), and the symbolic domain will record this alias information.
[0376] For the numeric domain, for the initial range, the value of len is 5, and the numeric domain records that the value range of i is 0 <= i < len, that is, 0 <= i < 5. For the pointer arithmetic constraint, when performing the pointer arithmetic new_vec.as_mut_ptr().add(i), the numeric domain is constrained by i < len to ensure that pointer access does not go out of bounds.
[0377] 3. Update the abstract domain.
[0378] 1) Numerical range update: In the for loop, according to the path condition i < len, the numerical range continuously updates the feasible range of i. In each loop, i increments, and the numerical range checks whether i still satisfies the condition i < len. If during the loop, the value of i exceeds len, the numerical range will detect the out-of-bounds risk and trigger the corresponding memory safety check.
[0379] 2) Symbolic range update: For the ownership transfer marker, after calling Vec::from_raw_parts(ptr, len, cap), the symbolic range marks that the ownership of ptr has been transferred to new_vec. For access permissions and lifetime information, in the for loop, the symbolic range records that the pointer of new_vec has read-write permissions, and after the drop(new_vec) call, it marks that the memory object mapped by new_vec has been released. For the target call operation marker, the symbolic range marks Vec::from_raw_parts(ptr, len, cap) as a target call operation because it involves ownership transfer and may lead to unsafe release. During taint analysis, new_vec is marked as a taint source. Subsequently, if the data of new_vec reaches an unsafe operation (such as out-of-bounds write), a memory safety vulnerability will be detected.
[0380] Through the above steps, the memory safety detector simulates the symbolic execution process, constructs the symbolic state of the target program, and continuously updates the abstract domain to detect potential memory safety issues.
[0381] It should be noted that APIs with potentially dangerous features usually have some obvious characteristics, such as they may bypass regular security checks, directly operate on underlying resources, or perform privilege escalation, etc. For example, functions like "from_raw_parts" can directly take over memory ownership, which bypasses the normal memory management mechanism and poses a relatively high security risk. API developers generally clearly indicate the usage scenarios, risks, and precautions of the API in the documentation. The memory safety detector can focus on detecting APIs that may cause security issues by reading the developer documentation corresponding to the API. If it is obtained through monitoring and analysis in the security report that a certain API has frequently caused security vulnerabilities during past use, then it will be regarded as a dangerous API, and the memory safety detector can refer to relevant security reports and vulnerability databases to identify such APIs.
[0382] Exemplarily, the memory safety detector can analyze the source code of the target program to check if it calls any known dangerous APIs. For example, a list of dangerous APIs can be established. When the memory safety detector performs static code scanning, once it finds that the target program calls an API in the list, it marks it as a dangerous API call. Additionally, the memory safety detector can also monitor API calls during the runtime of the target program. For example, it can intercept API calls through Hook technology and check the call parameters and context information. If it is found that the call parameters do not conform to the security specifications or there are abnormalities in the call context, the API call is marked as a dangerous API call in the detection information.
[0383] When performing "taint analysis", the memory safety detector can mark input sources that may contain sensitive information or untrusted data as taint sources. For example, user input, data returned from network requests, etc. may all be taint sources. The memory safety detector can track the propagation path of taint data in the program to understand how the data is passed from the taint source to other variables and functions, and analyze the processing operations that the taint data goes through during propagation to determine whether these operations will change the security of the data. For example, by performing symbolic execution on the target program to simulate the execution process of the target program and record the propagation of taint data. During symbolic execution, each variable and expression is marked as to whether it is taint data. If a variable is propagated from a taint source, then it is also marked as taint data.
[0384] Exemplarily, the memory safety detector can define the scope of unsafe operations according to the user-input unsafe operation definitions, such as releasing memory that has already been released, out-of-bounds access, using an uninitialized pointer, etc. When analyzing taint data, it can judge whether the taint data is directly involved in an unsafe operation based on the unsafe operation definitions. For example, if the taint data is used to calculate the subscript of an array and the subscript exceeds the boundary of the array, it means that the taint data has reached an unsafe operation. Similarly, when an unsafe operation is found to be executed, check whether the variables participating in the operation are taint data. If so, it is determined that the taint data has reached an unsafe operation.
[0385] Moreover, the memory safety detector can utilize abstract domains (including the symbolic domain and the numeric domain) to analyze the propagation and usage of taint data. The symbolic domain can record the mapping relationship between pointers and memory objects, and the numeric domain can manage the value range of variables. By analyzing the state of the abstract domain, the memory safety detector can judge whether taint data will lead to unsafe operations.
[0386] Furthermore, the memory safety detector can issue warnings or error messages based on corresponding function calls and their contexts, supplemented by path conditions and symbolic execution results to explain why the memory block or the pointer may cause security issues.
[0387] In addition, the memory safety detector can also analyze memory allocation and deallocation of the target program. Specifically, the memory safety detector can track memory allocation and deallocation operations in the target program to ensure that each allocated memory block has a corresponding deallocation operation to avoid memory leaks, and check the legality of the deallocation operation to prevent situations such as "use after free" or "double free".
[0388] Exemplarily, when the memory safety detector encounters a memory deallocation operation, it will mark the corresponding memory object as "released" in the symbolic domain, and append a logical constraint of "the current pointer is unavailable" or "the memory block has been recycled" in the numerical domain and path condition. If subsequent read and write operations on the same memory object are still detected on this path, it can be determined as a dangling pointer problem or unknown behavior, and corresponding alarm messages will be issued.
[0389] As an example, the input of the memory safety detector in the embodiments of the present invention can be a control flow graph CFG, and the output is a memory safety problem report R. The detection process of the memory safety detector can be as follows:
[0390] 1. Initialization:
[0391] 1.1 Create an empty "global abstract state table" to store path conditions, symbolic / numerical domain information.
[0392] 1.2 Add the program entry point to the queue to be analyzed.
[0393] 1.3 Initialize an empty report (R ← )
[0394] 2. Path analysis (generalized CFG traversal):
[0395] 2.1 Take a basic block B and a path state S from the queue.
[0396] 2.2 If B contains a branch instruction, clone the state S and add the corresponding branch constraint to the cloned path condition;
[0397] Add the new (B_true, S_true) and (B_false, S_false) to the queue.
[0398] 2.3 If B contains a memory allocation or pointer assignment operation, record the "allocation point / pointer association" in S.
[0399] 2.4 If the queue of basic blocks that have not been processed is still not empty, go to 2.1; otherwise, proceed to step 3.
[0400] 3. Symbolic execution:
[0401] 3.1 Perform symbolic execution on each path state S generated in 2:
[0402] (a) Simulate each instruction. In case of pointer arithmetic, add corresponding out-of-bounds constraints to the numerical domain;
[0403] (b) In case of a function call, check whether the ownership of memory objects is transferred and update the symbolic domain;
[0404] (c) In case of a pointer dereference scenario that may endanger safety (accessing after ownership is lost), add a corresponding risk entry to the report R.
[0405] 3.2 If all paths have been simulated, proceed to step 4.
[0406] 4. Detection of dangerous API calls:
[0407] 4.1 During symbolic execution, record the calls marked with "dangerous API";
[0408] 4.2 For the pointers passed into them, if they are marked with "tainted" or "to be verified", detect the subsequent usage of the pointers and related memory blocks according to the taint propagation rules;
[0409] 4.3 If an unsafe operation (such as double free, out-of-bounds write) related to the call is detected, write detailed analysis information to R.
[0410] 5. Memory allocation / deallocation analysis:
[0411] 5.1 Find all "allocated but not freed" memory objects in the symbolic domain:
[0412] If it is not freed on a reachable path, mark "memory leak" in the report R;
[0413] 5.2 Check the legality of "free" operations: If there is usage after free or double free, record the illegal path in the report R;
[0414] 5.3 If the program contains cross-function calls, transfer the merged memory object state to the called function and update the corresponding abstract state after return.
[0415] 6. End:
[0416] 6.1 Return the report R as the final analysis report.
[0417] Optionally, detecting potential concurrent security issues in the target program based on the global data and the lock dependency graph in step S52 includes:
[0418] Sub-step S521: Detect the lock dependency graph using a depth-first search algorithm to determine whether there is a potential deadlock in the target program;
[0419] Sub-step S522: Analyze the usage of conditional variables in the target program, and detect whether there is a race condition or deadlock in the target program according to the usage;
[0420] Sub-step S523: Perform atomic operation analysis on the target program, and detect whether the access of each thread in the target program to atomic variables is normal in a concurrent environment according to the lock dependency graph and the usage of atomic operations;
[0421] Sub-step S524: Analyze the access paths corresponding to shared variables in the target program, and detect whether there is concurrent access to the shared variables by each thread in the target program according to the lock dependency graph and the access paths;
[0422] Sub-step S525: Re-visit the lock dependency graph to detect certain deadlocks and conditional deadlocks in the target program;
[0423] Sub-step S526: Detect the atomicity of concurrent operations during the overlapping execution of multiple threads;
[0424] Sub-step S527: Generate a concurrent security detection report according to the detection results of each detection.
[0425] In the embodiment of the present invention, the concurrent security detector can use a depth-first search algorithm to perform cycle detection on the lock dependency graph to identify the lock acquisition order that may lead to deadlocks. A deadlock refers to an infinite waiting state that occurs when two or more threads are waiting for resources held by each other. Once a loop is found in the lock dependency graph, it indicates a circular wait, and the potential deadlock risk needs to be reported. For mutexes and read-write locks (rwlocks), the concurrent security detector can further distinguish different holding methods of read locks and write locks, and incorporate corresponding nodes or marks in the lock dependency graph to achieve more refined conflict judgment.
[0426] Condition variables are typically used in combination with locks to achieve synchronization between threads. A concurrent safety detector can analyze the usage of condition variables in a target program, examine their waiting and notification patterns, and determine whether there are race conditions or deadlocks in the target program. Condition variables allow a thread to continue execution when a certain condition is true and enter a waiting state when the condition is false. The concurrent safety detector ensures that the use of condition variables does not result in race conditions or deadlocks. A race condition refers to incorrect behavior that occurs when multiple threads access a shared resource simultaneously due to an indeterminate access order.
[0427] Atomic operations are another key mechanism in concurrent programming, used to ensure that operations in a multi-threaded environment are indivisible. The concurrent safety detector analyzes the atomic operations in the target program, identifies and classifies these operations as read, write, and read-write operations. Then, based on the lock dependency graph and the usage of each atomic operation, it detects whether the access of each thread in the target program to atomic variables is normal in a concurrent environment, ensuring that data consistency is not violated. Data consistency means that in a concurrent environment, all threads can see the latest state of the shared data.
[0428] The concurrent safety detector can also perform a competitiveness detection on the target program, analyze the access paths of shared variables in the target program, and based on the lock dependency graph and the access paths, detect whether there are concurrent accesses by each thread in the target program to the shared variables, and identify possible race conditions. Race conditions usually occur when multiple threads access and modify shared data simultaneously. The concurrent safety detector can ensure the safety of access to shared resources by analyzing the synchronization mechanism between basic blocks.
[0429] Exemplarily, the concurrent safety detector can maintain the access scenarios (read or write) of each thread to shared variables and cross-compare the access points of multiple threads; if it detects that two different threads perform write-write access or write-read access to the same variable without any lock, atomic guarantee, or other synchronization means, a race can be determined; if the access order is unpredictable, this race is likely to lead to uncertainty in program behavior. The concurrent safety detector can clarify the corresponding thread cross positions and possible data inconsistency problems in the detection report. Among them, atomic guarantee refers to operations that are executed in an indivisible manner in concurrent programming. These operations will not be interrupted or interfered between multiple threads. Even if multiple threads access or modify the same data simultaneously, these operations can still ensure consistency, such as atomic instructions (Compare-and-Swap, CAS) provided by the CPU, etc.
[0430] In addition, after performing conditional analysis, atomic operation analysis, and race condition detection on the target program, the concurrent security detector can perform deadlock detection again. Exemplarily, the concurrent security detector can execute the DFS algorithm on the lock dependency graph. If a loop containing k lock resources is found, a potential "circular wait" deadlock is reported.
[0431] The concurrent security detector can further perform reachability analysis on the target program by combining call stack information to distinguish between inevitable deadlocks and conditional deadlocks. Among them, an inevitable deadlock means that a loop must appear on certain branches; a conditional deadlock occurs only when specific orders and conditions are met. If the concurrent security detector determines that the deadlock path is controllable or probabilistic, corresponding prompt information can be generated to give the user a hint of possible "potential deadlock".
[0432] In the case where read locks and write locks coexist, the concurrent security detector can equally incorporate read lock sharing and write lock exclusivity into the lock dependency graph and uniformly determine whether an insoluble waiting loop is formed, thereby more accurately identifying deadlocks.
[0433] The concurrent security detector can also perform atomicity analysis on the target program. Specifically, during the overlapping execution of multiple threads, the concurrent security detector detects the atomicity of concurrent operations to ensure that these operations will not be interrupted by other threads during execution. If some sequences need to be executed atomically as a whole but there are no locks or appropriate atomic instructions, the concurrent security detector can determine that the atomicity of the sequence is violated and generate corresponding prompt information, such as marking the sequence as "atomicity violated" and suggesting using stronger synchronization primitives or adding locks before and after this section of operations. By analyzing the interactions between threads, the concurrent security detector can identify possible atomicity violations and provide solutions to ensure the integrity of operations.
[0434] As an example, assume that the target program contains multiple thread functions that operate on shared resources and use different types of locks, as shown below:
[0435] # Define locks
[0436] lock_A = threading.Lock()
[0437] lock_B = threading.Lock()
[0438] lock_C = threading.Lock()
[0439] # Shared variable
[0440] shared_variable = 0
[0441] def thread_1():
[0442] global shared_variable
[0443] lock_A.acquire()
[0444] lock_B.acquire()
[0445] # Simulate operations
[0446] shared_variable += 1
[0447] lock_B.release()
[0448] lock_A.release()
[0449] def thread_2():
[0450] global shared_variable
[0451] lock_B.acquire()
[0452] lock_C.acquire()
[0453] # Simulate operations
[0454] shared_variable -= 1
[0455] lock_C.release()
[0456] lock_B.release()
[0457] def thread_3():
[0458] global shared_variable
[0459] lock_C.acquire()
[0460] lock_A.acquire()
[0461] # Simulate operations
[0462] shared_variable = 2
[0463] lock_A.release()
[0464] lock_C.release()
[0465] # Create threads
[0466] t1 = threading.Thread(target=thread_1)
[0467] t2 = threading.Thread(target=thread_2)
[0468] t3 = threading.Thread(target=thread_3)
[0469] # Start threads
[0470] t1.start()
[0471] t2.start()
[0472] t3.start()
[0473] # Wait for threads to finish
[0474] t1.join()
[0475] t2.join()
[0476] t3.join()
[0477] print(f"Final value of shared_variable: {shared_variable}")
[0478] In the embodiments of the present invention, the concurrent security detector performs concurrent security detection on the target program of the above example based on the global data and the lock dependency graph. The specific detection process is as follows:
[0479] 1. Use the depth-first search algorithm to detect the lock dependency graph to determine whether there is a potential deadlock in the target program.
[0480] The process of constructing the lock dependency graph is as follows:
[0481] Thread 1: First acquire lock_A and then acquire lock_B, and add a directed edge from A to B in the lock dependency graph. Thread 2: First acquire lock_B and then acquire lock_C, and add a directed edge from B to C. Thread 3: First acquire lock_C and then acquire lock_A, and add a directed edge from C to A.
[0482] At this time, the lock dependency graph forms a loop: A→B→C→A.
[0483] Depth - First Search (DFS) Detection: Use the DFS algorithm to traverse the lock - dependency graph. When a loop is found in the graph, it indicates the existence of circular waiting and a potential dead - lock risk is reported. In this example, through DFS, the loop A→B→C→A can be detected, and a potential dead - lock is determined.
[0484] 2. Analyze the usage of condition variables in the target program. Based on the usage, detect whether there is a race condition or dead - lock in the target program.
[0485] In this example, no condition variables are used, so there are no race conditions or dead - locks caused by improper use of condition variables. If there are condition variables in the program, the concurrent - safety detector will check their waiting and notification patterns to determine whether there is a race condition or dead - lock. For example, if one thread is waiting for a certain condition variable while another thread does not correctly notify that condition variable to the previous thread, it may lead to a dead - lock.
[0486] 3. Conduct atomic - operation analysis on the target program. Based on the lock - dependency graph and the usage of atomic operations, detect whether the access of each thread in the target program to atomic variables is normal in a concurrent environment.
[0487] If there are atomic operations in the program, the concurrent - safety detector will identify and classify these operations as read, write, and read - write operations. Then, based on the lock - dependency graph and the usage of atomic operations, it will detect whether the access of each thread to atomic variables is normal. For example, if one thread is performing an atomic write operation while another thread is also writing to the same atomic variable without a proper synchronization mechanism, it may corrupt the data consistency.
[0488] 4. Analyze the access paths corresponding to shared variables in the target program. Based on the lock - dependency graph and the access paths, detect whether there are concurrent accesses by each thread in the target program to the shared variables.
[0489] Thread 1: After obtaining lock_A and lock_B, perform an increment operation on shared_variable.
[0490] Thread 2: After obtaining lock_B and lock_C, perform a decrement operation on shared_variable.
[0491] Thread 3: After obtaining lock_C and lock_A, perform a multiplication - by - 2 operation on shared_variable.
[0492] Detect concurrent access: By analyzing the lock dependency graph and access paths, check whether there are multiple threads accessing shared_variable concurrently without a proper synchronization mechanism. In this embodiment, each thread uses a lock to protect access to shared_variable, so there is no concurrent access problem. However, if a certain thread does not use a lock, or the lock is used improperly, it may lead to concurrent access and thus a race condition.
[0493] 5. Re-visit the lock dependency graph to detect inevitable deadlocks and conditional deadlocks in the target program.
[0494] Use the DFS algorithm again to detect the lock dependency graph and confirm whether there is a deadlock loop. In this example, the loop A→B→C→A has been detected before, indicating a potential deadlock. Perform reachability analysis by combining call stack information to distinguish the potential deadlock as an inevitable deadlock or a conditional deadlock. If the loop must appear on certain branches, it is an inevitable deadlock; if the deadlock can occur only when specific orders and conditions are met, it is a conditional deadlock. In this example, if three threads start simultaneously and execute in a specific order, a deadlock will occur, so it can be determined as a conditional deadlock.
[0495] 6. Detect the atomicity of concurrent operations during the overlapping execution of multiple threads.
[0496] In this example, there is no sequence that obviously needs to be executed atomically as a whole. If there is such a sequence in the program, the concurrent security detector will check whether there is a lock or a proper atomic instruction to ensure atomicity for this sequence. If not, it will determine that the atomicity of this sequence is violated and generate corresponding prompt information, such as marking "Atomicity Violated" and suggesting using stronger synchronization primitives or adding locks.
[0497] 7. Generate a concurrent security detection report based on the detection results of each item. The content of the concurrent security detection report can include:
[0498] 1) A potential deadlock is detected, and the deadlock loop is A→B→C→A, which belongs to a conditional deadlock.
[0499] 2) No conditional race or deadlock problems caused by improper use of conditional variables are found.
[0500] 3) No data consistency problems caused by improper use of atomic operations are found.
[0501] 4) The access of each thread to the shared variable is synchronized by a lock, and no concurrent access problems are found.
[0502] 5) No sequences with violated atomicity are found.
[0503] Through the above steps, the concurrent security detector has comprehensively detected the concurrent security of the target program and generated a corresponding detection report.
[0504] Optionally, determining whether there is a potential deadlock in the target program in sub-step S521 includes:
[0505] In the case where a loop is detected in the lock dependency graph, marking the loop as a potential deadlock;
[0506] Generating a first warning message according to the acquisition and release order of the locks corresponding to the loop and the corresponding thread calls.
[0507] The concurrent security detector can use the depth-first search algorithm to detect loops in the lock dependency graph. Specifically, once a loop is found in the graph, it indicates the existence of circular waiting and the potential deadlock risk needs to be reported. For example, generating a first warning message according to the acquisition and release order of the locks corresponding to the loop and the corresponding thread calls. The first warning message is used to prompt the potential deadlock risk. For example, the first warning message can include a deadlock prompt and mark the corresponding deadlock loop and deadlock type, such as "Potential deadlock detected, the deadlock loop is A → B → C → A, belonging to conditional deadlock".
[0508] For mutexes and rwlocks, the concurrent security detector can further distinguish different holding methods of read locks and write locks, incorporate corresponding nodes or marks in the graph to achieve more refined conflict judgment.
[0509] Optionally, detecting whether there is a race condition or deadlock in the target program according to the usage in sub-step S522 includes:
[0510] When a first thread performs a predefined wait or wake-up operation on a first conditional variable in the target program, recording the dependency of the first thread on the first conditional variable in the lock dependency graph and tracking whether the lock held by the first thread is correctly released;
[0511] When a predefined notification operation is executed in the target program, determining whether the awakened second thread can reacquire the lock and execute safely;
[0512] When there is at least one conditional variable wait in the target program accompanied by lock acquisition and release operations, detecting the conditional dependencies and lock holding situations among threads in the lock dependency graph to capture potential deadlock problems.
[0513] It is understandable that condition variables are usually used in combination with locks to achieve synchronization between threads. A concurrency safety detector can analyze the usage of condition variables and check their waiting and notification patterns. Condition variables allow a thread to continue execution when a certain condition is true and enter a waiting state when the condition is false. The concurrency safety detector ensures that the use of condition variables does not lead to race conditions or deadlocks. A race condition refers to incorrect behavior that occurs when multiple threads access a shared resource simultaneously due to an indeterminate access order.
[0514] When performing condition variable analysis on a target program, the concurrency safety detector can focus on the following key points:
[0515] 1. Condition variable wait / wake calls: When a thread calls a wait series of interfaces to wait, the concurrency safety detector can record the current thread's dependency on a certain condition in the lock dependency graph or synchronization model and track whether the lock it holds is released in a timely manner.
[0516] 2. Notification and lock interaction: When calling notify (notification) or notify_all, the concurrency safety detector needs to confirm whether the awakened thread can correctly reacquire the lock and continue execution to prevent race disputes or deadlocks in complex waiting scenarios.
[0517] 3. Integration with lock analysis: If there are multiple condition variable waits in the target program along with a complex locking and unlocking order, the concurrency safety detector can combine "condition dependencies" and "lock holdings" in the lock dependency graph to infer unreachable or forever waiting situations, thereby capturing potential deadlocks or thread starvation problems.
[0518] As an example, assume the target program is as follows:
[0519] / / Shared resources and synchronization mechanisms
[0520] shared_mutex rw_lock; / / Read-write lock
[0521] condition_variable cv_producer, cv_consumer;
[0522] int buffer = 0;
[0523] bool data_ready = false;
[0524] / / Producer thread
[0525] void producer(int id) {
[0526] unique_lock<shared_mutex> lock(rw_lock);
[0527] while (true) {
[0528] lock.lock(); / / Acquire the write lock before producing data
[0529] buffer++; / / Simulate time-consuming production operation
[0530] cout << "Producer " << id << " produced: " << buffer << endl;
[0531] data_ready = true;
[0532] cv_consumer.notify_all(); / / Notify consumers
[0533] cv_producer.wait(lock, []{ return!data_ready;}); / / Wait for consumers to process, without releasing the write lock here
[0534] lock.unlock();
[0535] }
[0536] }
[0537] / / Consumer thread
[0538] void consumer(int id) {
[0539] unique_lock<shared_mutex> lock(rw_lock);
[0540] while (true) {
[0541] lock.lock_shared(); / / Acquire the read lock while waiting for data
[0542] / / Wait for data to be ready
[0543] cv_consumer.wait(lock, []{ return data_ready;});
[0544] / / Simulate time-consuming consumption operation
[0545] cout << "Consumer " << id << " consumed: " << buffer << endl;
[0546] data_ready = false;
[0547] cv_producer.notify_all(); / / Notify the producer
[0548] lock.unlock_shared();
[0549] }
[0550] }
[0551] int main() {
[0552] thread p1(producer, 1);
[0553] thread c1(consumer, 1);
[0554] thread c2(consumer, 2);
[0555] p1.join();
[0556] c1.join();
[0557] c2.join();
[0558] return 0;
[0559] }
[0560] The concurrent safety detector detects deadlocks in the target program through the following steps:
[0561] 1. Construct a lock dependency graph (distinguishing read / write locks).
[0562] Producer thread: Acquire the write lock (lock.lock()) → Node W (write lock), do not release the lock while waiting for the condition variable → The lock dependency retains W;
[0563] Consumer thread: Acquire the read lock (lock.lock_shared()) → Nodes R1, R2 (read locks);
[0564] The lock dependency graph is as follows: W → R1 → W → R2 → W →... (Since the producer does not release the write lock, the consumer cannot acquire the read lock, forming a circular wait).
[0565] 2. Detect condition variable wait / wake calls in the target program.
[0566] Producer waiting: When calling cv_producer.wait(lock, ...), the write lock is not released (lock is a unique_lock). The unique_lock automatically releases the lock when waiting and reacquires it after waking up. However, in the example, the producer does not release the lock after wait, preventing the consumer from acquiring the read lock, indicating a race condition in the target program and that the data update and waiting logic are not correctly synchronized.
[0567] Consumer waiting: When calling cv_consumer.wait(lock, ...), the read lock is automatically released (lock_shared is a shared_lock and needs to be manually managed).
[0568] 3. Detect the interaction between notifications and locks.
[0569] Producer notifies consumer: When calling cv_consumer.notify_all(), the consumer is awakened but needs to reacquire the read lock. The producer does not release the write lock, so the consumer cannot acquire the read lock, resulting in the inability to execute even after waking up.
[0570] Consumer notifies producer: When calling cv_producer.notify_all(), the producer is awakened but needs to reacquire the write lock.
[0571] 4. By combining "conditional dependencies" and "lock holdings" in the lock dependency graph, infer situations of unreachability or perpetual waiting.
[0572] Deadlock derivation: The producer holds the write lock W, produces data, and then notifies the consumer. After being awakened, the consumer attempts to acquire the read lock R1 or R2, but the write lock W is not released. The producer waits for!data_ready in cv_producer.wait, but the consumer cannot modify data_ready (because it cannot acquire the read lock). A loop of W → R1, R2 → W is formed in the lock dependency graph, resulting in a deadlock. This deadlock is an inevitable deadlock, where the producer and the consumer wait for each other to release the lock.
[0573] 5. Generate concurrent safety detection results
[0574] Race condition detection: The producer does not correctly release the write lock when waiting for the condition variable, preventing the consumer from acquiring the read lock. As a result, the concurrent safety detector can effectively identify concurrent safety issues such as race conditions and deadlocks through the above steps.
[0575] As an example, the input of the concurrent security detector in the embodiments of the present invention can be a control flow graph CFG, and the output is a concurrent security issue report R, including information such as deadlock risk, race condition, and atomicity violation. The detection process of the concurrent security detector can be as follows:
[0576] 1. Initialization:
[0577] 1.1 Extract the control flow information of P and the thread creation points, and construct an overall graph structure that can reflect thread interactions.
[0578] 1.2 Initialize an empty concurrent security report (R ← );
[0579] 1.3 Initialize a lock dependency graph G and other auxiliary data structures (such as read-write sets, atomicity records, condition variable wait tables, etc.).
[0580] 2. Lock analysis:
[0581] 2.1 In the multi-threaded control flow, scan the lock acquisition operation acquire_lock(L) encountered by each thread:
[0582] (a) If the current thread holds another lock L0 at the same time, add a directed edge L0 → L to the lock dependency graph G;
[0583] (b) If unlock(L0) is encountered later, delete the dependency on L0 in G;
[0584] 2.2 If a cycle is detected in the graph G, write the relevant lock order and the corresponding thread call record into R, mark it as a potential deadlock, and generate a first warning message.
[0585] 3. Condition variable analysis:
[0586] 3.1 For the wait(cond) operation: Record the waiting state of the current thread (including the lock information it holds), and mark "thread T waits for cond" in the condition variable wait table;
[0587] 3.2 When notify(cond) or notify_all(cond) is executed, match the awakened threads according to the wait table, and confirm whether the threads can reacquire the lock and execute safely;
[0588] 3.3 If it is detected that the lock is not released as expected during the waiting period or the thread call order between threads causes a deadlock, insert the corresponding warning information into R.
[0589] 4. Atomic operation analysis:
[0590] 4.1 Classify and record all atomic operations in the program (such as reads / writes, etc.), and update the global "Atomic Variable Access Table", where the Atomic Variable Access Table is used to record the atomic operations of variables, such as read or write operations;
[0591] 4.2 If an atomic operation sequence needs to specify a memory order, but is actually used improperly or is mismatched in parallel with locks, it is determined as a potential consistency problem and registered in R;
[0592] 4.3 On multi-threaded cross paths, if the access to the same atomic variable exhibits undefined behavior (such as incorrect memory order), it can be marked as "Possible Data Race".
[0593] 5. Race Condition Detection:
[0594] 5.1 Establish a read / write access table for shared variables (including ordinary global static variables or multi-thread visible objects);
[0595] 5.2 If it is detected that two different threads perform concurrent write-write or read-write access to the same variable without any synchronization mechanism (excluding atomic or lock control), report a race;
[0596] 5.3 The detector adds the access point and thread context to R to assist the user in locating the specific source of the race and the possible error impact.
[0597] 6. Deadlock Detection:
[0598] 6.1 Revisit the lock dependency graph G or the resource waiting graph (if condition variables, locks, etc. are all mapped to resource nodes), and perform cycle detection again;
[0599] 6.2 For the detected loops, distinguish between inevitable deadlocks and conditional deadlocks by combining thread reachability analysis;
[0600] 6.3 For each potential deadlock path, record the lock acquisition order and thread call stack in R, and prompt possible solutions (such as unifying the lock acquisition order or avoiding nested locks, etc.).
[0601] 7. Atomicity Analysis:
[0602] 7.1 During the overlapping execution of multiple threads, perform simulation or symbolic analysis on the critical code segments that need to be executed atomically;
[0603] 7.2 If it is detected that the code segment can be inserted by other threads to break atomicity, report "Atomic Operation Broken" to R;
[0604] 7.3 Suggest according to the context: Use stronger synchronization (such as mutex locks or more strict memory order) to ensure atomicity.
[0605] 8. End: The concurrent security risks (deadlocks, race conditions, atomicity violations, etc.) obtained by integrating the above steps are uniformly stored in report R; and report R is returned as the final analysis output.
[0606] Optionally, the step S53 of using the global data to respectively determine the value ranges corresponding to the respective variables in the target program and constructing a linear constraint system includes:
[0607] Sub-step S531: Through a numerical security detector, an initial value range is respectively assigned to each variable in the target program;
[0608] Sub-step S532: During the process of traversing each basic block in the target program, the value ranges of the variables are adjusted according to arithmetic instructions and branch conditions;
[0609] Sub-step S533: Convert the operation conditions corresponding to the established comparison instructions or arithmetic instructions in the target program into linear inequalities;
[0610] Sub-step S534: Construct a linear constraint system according to the value ranges of the respective variables and the linear inequalities.
[0611] In an embodiment of the present invention, when a numerical security detector performs numerical security detection on a target program, it can first assign an initial interval to all variables in the target program. For example, the unconstrained integer range is represented by (-∞, +∞). If the compiler or language environment can infer finer type boundaries (such as u32, i64), then its initial interval is set to the corresponding valid value range.
[0612] As the traversal and statement interpretation of each basic block in the target program proceed, the numerical security detector continuously adjusts the variable intervals according to arithmetic instructions and branch conditions. For example, when something like "y = x + 2" appears, if the current interval of x is [a, b], then the interval of y can be updated to [a + 2, b + 2]. If a branch condition (if x>10) is encountered, then on this branch path, the lower bound of x is updated to max(11, previous lower bound) to narrow the range of values that x can take. Considering complex control flows with branches and loops, the numerical security detector can perform "least upper bound" or "greatest lower bound" merging operations on the intervals during loop iterations or multi-branch merges until a stable state where no further changes occur (i.e., the intervals converge). In this process, upper / lower approximations in abstract interpretation are often used to balance analysis efficiency and precision.
[0613] As an example, assume that the numerical security detector performs iterative analysis on the target program according to arithmetic instructions and branch conditions, and the execution logic for adjusting variable intervals is as follows:
[0614] # Initial interval: x [0, 100]
[0615] x = Interval(0, 100)
[0616] # Loop condition: x < 70
[0617] while x.upper < 70:
[0618] # Branch 1: x > 50 → x += 10
[0619] branch1 = x.copy()
[0620] branch1.lower = max(branch1.lower, 51)
[0621] branch1.upper = branch1.upper
[0622] branch1.lower += 10
[0623] branch1.upper += 10
[0624] # Branch 2: x ≤ 50 → x -= 5
[0625] branch2 = x.copy()
[0626] branch2.upper = min(branch2.upper, 50)
[0627] branch2.lower -= 5
[0628] branch2.upper -= 5
[0629] # Merge branch intervals (minimum lower bound & maximum upper bound)
[0630] merged = Interval(
[0631] lower = min(branch1.lower, branch2.lower),
[0632] upper = max(branch1.upper, branch2.upper) )
[0634] # Apply global limit: x ∈ [20, 70]
[0635] merged.lower = max(merged.lower, 20)
[0636] merged.upper = min(merged.upper, 70)
[0637] # Check if the interval converges
[0638] if merged == x:
[0639] break
[0640] x = merged
[0641] In the above example, the initial state is: the interval of variable x is [0, 100], and the loop condition is x.upper < 70 (initially satisfied).
[0642] 1) First iteration:
[0643] For branch 1: The condition is x > 50, so the interval is adjusted. The lower bound is increased to max(0, 51) = 51, and then in the increment operation, 51 + 10 = 61 → x [61, 110];
[0644] For branch 2: The condition is x ≤ 50, so the interval is adjusted. The upper bound is decreased to min(100, 50) = 50, and then in the decrement operation, 50 - 5 = 45 → x [-5, 45];
[0645] Merge the intervals of branches 1 and 2: The lower bound is min(61, -5) = -5, and the upper bound is max(110, 45) = 110, so the merged result is x [-5, 110]; Apply the global limit to the merged result: The lower bound is max(-5, 20) = 20, and the upper bound is min(110, 70) = 70, so the final interval: x [20, 70].
[0646] 2) Second iteration:
[0647] For branch 1: The condition is x > 50 → the current interval is [20, 70], so the interval is adjusted. The lower bound is increased to max(20, 51) = 51, and then in the increment operation, 51 + 10 = 61 → x [61, 80];
[0648] For branch 2: If the condition is x ≤ 50 → the current interval is [20, 70], then the interval is adjusted. The upper bound is reduced to min(70, 50) = 50. Then, for the decrement operation, 50 - 5 = 45 → x [15, 45];
[0649] Merge the intervals of branches 1 and 2: The lower bound is min(61, 15) = 15, and the upper bound is max(80, 45) = 80. So the merged result is x [15, 80]; Apply the global limit to the merged result: The lower limit is adjusted to max(15, 20) = 20, and the upper limit is adjusted to min(80, 70) = 70. Then the final interval is x [20, 70], which is the same as the previous round, indicating interval convergence.
[0650] The final interval is x [20, 70]. Then x.upper = 70 no longer satisfies the condition < 70, and the loop terminates.
[0651] During the whole processing, the numerical safety detector processes each branch separately and updates the interval according to the conditional constraints and arithmetic operations. In the example, branch 1 raises the lower bound through max, and branch 2 reduces the upper bound through min.
[0652] The interval merging strategy is: Take the minimum value of all branch intervals as the new lower bound, and take the maximum value of all branch intervals as the new upper bound. In the example, the merged interval is [-5, 110]. The interval is adjusted by the numerical processor, which can superimpose external restrictions (such as array out-of-bounds checks) and truncate the interval through max / min. In the example, the interval is restricted by max(..., 20) and min(..., 70). When making the convergence determination, compare the current interval with the previous round's interval. If they are the same, it means the interval converges, and the iteration terminates. In this embodiment, the interval does not change after the second iteration and reaches a stable state.
[0653] In the above example, the numerical safety detector performs interval propagation on the conditions and operations of each branch through branch-independent analysis; merges the branch intervals through the minimum lower bound and the maximum upper bound to ensure safety; superimposes external restrictions to narrow the feasible interval; and achieves fixed-point convergence through interval comparison. This process balances the analysis accuracy (through branch refinement) and efficiency (through approximate merging), which is a typical application of abstract interpretation in numerical safety detection.
[0654] After obtaining the value ranges of each variable, the numerical safety detector further constructs a linear constraint system to describe the mutual relationships and operation conditions among the variables.
[0655] Specifically, in scenarios where more refined connections between variables need to be captured, the numerical safety detector enhances the accuracy and strength of diagnosis by transforming the conditions related to comparison or arithmetic instructions into linear inequalities and incorporating them into a unified constraint system. For example, during the constraint construction phase, when the numerical safety detector detects the comparison instruction x < y + 1 in MIR, it can be abstracted as the linear inequality x - y ≤ 0 (since x < y + 1 is equivalent to x - y - 1 < 0, which can be further written as x - y ≤ 0). Similarly, for arithmetic instructions such as addition, subtraction, multiplication, and division, the variable relationships can be summarized as linear equations or inequalities in combination with interval information. For example, when z = x + y, it can be represented as the linear equation z - x - y = 0, and the consistency of this variable relationship is maintained during the solution process. In addition, to prevent the analysis from being distorted due to the boundary conditions of data types, the program detection system will automatically generate hard constraints in the background, such as x ≤ MaxType(x) (this constraint condition always exists during the execution of the target program), to ensure the accuracy of overflow detection.
[0656] Optionally, detecting potential numerical safety issues in the target program according to the linear constraint system in step S53 and generating a numerical safety detection result includes:
[0657] Sub-step S535: Solve the linear constraint system to determine the first value range of the operation operands corresponding to each arithmetic instruction in the target program and the second value range of the operation results;
[0658] Sub-step S536: Analyze whether the first value range and the second value range fall within the legal range;
[0659] Sub-step S537: In the case where the first value range or the second value range exceeds the legal range, determine that there are numerical safety issues in the target program and record them.
[0660] After constructing the linear constraint system, the numerical safety detector can solve the linear constraint system to locate the numerical states that cannot satisfy all the constraint conditions simultaneously, thereby discovering potential numerical violations in functions or expressions at an early stage, such as out-of-bounds access or arithmetic anomalies.
[0661] Specifically, the numerical detector can use Figure 3 the solver in to solve the linear constraint system, determine the first value range of the operation operands corresponding to each arithmetic instruction in the target program and the second value range of the operation results, and locate the numerical safety issues in the target program by judging whether the first value range and the second value range fall within the legal range.
[0662] Exemplarily, during the constraint merging and iteration process, the numerical safety detector can utilize a linear constraint solver to merge the newly added linear equalities or inequalities, thereby constructing a joint constraint system for all linear conditions under the current path. After the system is updated, the numerical safety detector can further tighten the interval information based on the solution results. If the solution results show that the upper or lower bound of a certain variable can be narrowed, the value range of this variable will be adjusted accordingly, thereby affecting the construction and solution of the next round of constraints. Through this dynamic update mechanism, the numerical safety detector can perform multiple rounds of iterative analysis within a function. Especially when encountering loops or recursive calls, it continuously approaches the fixed point in the two-way propagation of constraints and intervals, thereby achieving a more robust analysis result.
[0663] During the numerical safety detection process, polyhedral domains (such as Octagon Domain, Polka Polyhedra, etc.) in the abstract domain library (such as Apron) are used to represent and maintain these linear inequalities.
[0664] For example, when relationships such as "z = x + y" or "x - y ≤ 0" are generated, the numerical safety detector can call the abstract operations of Apron (such as adding dimensions, assignment, meet operation, etc.) and incorporate them into the corresponding polyhedral abstract environment.
[0665] If the instruction represents z = x + y, the numerical safety detector creates a "z - x - y = 0" in the linear expression structure and performs an assignment operation; if the instruction represents x < y + 1, it is transformed into x - y - 1 < 0, that is, x - y ≤ 0, and the meet operation is used to intersect with the current abstract environment, thereby narrowing the solution space; at the loop iteration or branch convergence point, the detector repeats the join or meet operations provided by Apron to make the constraints between variables continuously converge to a stable state. For specific examples, refer to the relevant examples in the aforementioned sub-steps S531 to S534.
[0666] By combining with the abstract domain library, the numerical safety detector can not only effectively update the interval information but also capture the linear constraint relationships between different variables in more dimensions, thereby achieving higher accuracy in numerical safety detection.
[0667] In addition, to achieve more precise and complex constraint inference, the numerical safety detector can also interact with external solvers (such as SMT solvers like Z3). Exemplarily, the numerical safety detector can submit the set of linear inequalities of the current path to the solver to obtain the feasibility result of the constraint system or a feasibility model for verifying whether a certain variable meets specific conditions. Based on this, the numerical safety detector further strengthens the interval analysis result. For example, when the solver proves that the constraint conditions on a certain path cannot be satisfied simultaneously, that path is determined to be unreachable; if the solver confirms that the maximum feasible value of a certain variable x is N, the numerical safety detector will update the interval of x to [lower limit, N]. Through this combined strategy of numerical domain analysis and SMT constraint inference, while ensuring the overall efficiency, the numerical safety detector can use the dynamic cleaning mechanism of ownership and lifecycle to delete inactive abstract information at the appropriate time, reduce the analysis overhead and ensure the convergence speed, significantly improve the analysis accuracy, and thus achieve more accurate error root cause location.
[0668] Based on the information obtained from the aforementioned interval analysis and linear constraint solving, the numerical safety detector systematically reviews the numerical operations in the target program, focusing on evaluating whether the operation operands and operation results fall within the legal range, and if they exceed the range, it is regarded as a potential error scenario. By analyzing the operands and results of the operations, the numerical safety detector can identify possible division-by-zero errors and overflow problems.
[0669] On the basis of combining interval analysis and linear constraint solving, the numerical safety detector can systematically review the numerical operations in the target program to locate potential dangerous operations and improve the safety and reliability of the target program. In terms of out-of-bounds and overflow detection, when the operand exceeds the boundary of the defined data type (for example, exceeding the upper and lower limits of a 32-bit signed integer), the numerical safety detector can identify and report possible integer overflow or underflow risks. In addition, if a variable is used as an array subscript but does not meet the constraint that the array length is greater than the subscript (i.e., array_length > index), the numerical safety detector can also trigger an out-of-bounds alarm to avoid program crashes or data leaks caused by illegal access.
[0670] For division-by-zero checks, when the program contains division or remainder operations, the numerical safety detector can automatically add the inequality constraint divisor ≠ 0 to ensure that the denominator or divisor of the operator is always valid. If it is found through analysis that the interval of the divisor may contain 0, or the value of the divisor is indeed 0 under a certain path, the numerical safety detector can mark that path. For example, record the risk of "possible division by zero" and provide a corresponding warning.
[0671] In the scenario of inequality violation, the numerical safety detector can also identify potential conflicts in the program logic. For example, when a function or expression explicitly requires certain conditions to be met (such as x < y), but these conditions cannot be satisfied simultaneously after being jointly solved with other constraints on the program path, the numerical safety detector can generate corresponding prompt messages indicating that these conditions may not be achievable due to insecure input or logical errors.
[0672] As an example, the input of the numerical safety detector in the embodiments of the present invention can be a control flow graph CFG, and the output is a numerical safety problem report R, including possible out-of-bounds, overflow, division-by-zero risks, etc. The detection process of the numerical safety detector can be as follows:
[0673] 1. Initialization:
[0674] 1.1 Initialize the analysis report (R ← )
[0675] 1.2 Create an abstract environment AE, and use Apron's Interval Domain to store the initial intervals of each variable:
[0676] (a) For variable v, if the type range can be inferred (such as i32, u64), set AE[v] to the corresponding [min, max];
[0677] (b) Otherwise, set AE[v] to (-∞, +∞);
[0678] 1.3 Prepare a linear constraint management structure LC for subsequent collection of constraints generated by comparison and arithmetic instructions;
[0679] 1.4 If an external solver (SMT) or polyhedron domain is required, initialize the corresponding interfaces (such as the Z3 context or Apron's polyhedron abstraction manager).
[0680] 2. Interval analysis:
[0681] 2.1 Traverse the basic blocks and control flow graph of the program, and process each instruction as follows:
[0682] (a) If it is an arithmetic assignment and y depends on x, read the interval of x in AE and update the interval of y based on it;
[0683] (b) If it is a branch condition, update the upper and lower limits of the interval on the branch that satisfies the condition; maintain the original information on the branch that does not satisfy the condition;
[0684] (c) Perform interval merging at loop or branch convergence points (such as taking the intersection or union of upper and lower bounds, depending on the language semantics), and repeat the iteration until the information in AE no longer changes (interval convergence).
[0685] 2.2 During this period, if there is a significant contraction in AE[v], it indicates that most paths have strict restrictions on v, which can reduce the subsequent analysis overhead; if AE[v] exceeds the boundary range of the variable type, report the overflow risk in R.
[0686] 3. Linear constraint system:
[0687] 3.1 Collect all constraints related to comparison or arithmetic instructions and record them in the linear constraint management structure LC:
[0688] (a) Convert comparison instructions in MIR into linear inequalities;
[0689] (b) Convert assignment instructions into linear equations;
[0690] (c) Add additional constraints to the type boundaries that may overflow;
[0691] 3.2 Store and merge LC in Apron's polyhedron domain or an abstract environment LAE with a linear solving interface:
[0692] (a) Each time a new constraint is added, perform a meet operation on LAE to narrow the solution space;
[0693] (b) If the meet result indicates that the constraints are unsatisfiable (the solution space is empty), mark the corresponding path as unreachable;
[0694] (c) When it is found that the upper and lower bounds of a variable are further tightened, synchronize and update this information to the abstract environment.
[0695] 4. Interactive solving:
[0696] 4.1 If more precise analysis is required, the detector will send the current path LC to an external solver (such as Z3):
[0697] (a) The solver returns feasibility: if it is infeasible, prune the path; if it is feasible, obtain a partial model;
[0698] (b) If it is feasible, update the interval range of relevant variables in the abstract environment;
[0699] 4.2 If new convergent constraints are found after multiple rounds of iteration, they can be passed to the solver again for strengthening;
[0700] 4.3 Every time an unsatisfiable constraint is encountered, directly report the logical conflict or potential path error in R.
[0701] 5. Numerical calculation security:
[0702] 5.1 Identify all key numerical operations, such as division / modulo (divisor ≠ 0) and array subscripts (index <array_length):
[0703] (a) Check the divisor interval in AE. If it contains 0, record "potential division by zero";
[0704] (b) View the index in LAE <array_length 的约束是否可满足;若出现 index≥array_length,则报告越界风险;
[0705] (c) Detect whether arithmetic operations exceed the bounds of the variable type and record possible overflow.
[0706] 5.2 If linear constraints indicate that some declared conditions cannot be met, the user is prompted that there may be invalid input or unsafe conditions.
[0707] 6. End:
[0708] 6.1 Write the numerical status and potential unsafe information in AE and LAE into report R;
[0709] 6.2 Provide detailed descriptions of paths and variables for explicitly detected problems (out-of-bounds, division by zero, overflow, etc.);
[0710] 6.3 Return the analysis report R for use by the compiler or subsequent stages of the static analysis workflow.
[0711] In summary, an embodiment of the present invention provides a program detection method, which performs static analysis with the intermediate intermediate representation (MIR) of the Rust compiler as the core. Specifically, the source code of the target program is first parsed based on the package manager to generate MIR, and the MIR is analyzed to construct a control flow graph. The target program is subjected to fixed-point iteration analysis based on the control flow graph, and the type and life cycle information at the MIR level are deeply mined to determine the state data corresponding to each function in the target program, and the state data is integrated into global data; at least one of memory safety detection, concurrency safety detection and numerical safety detection is performed on the global data, and a detection result is generated. The embodiment of the present invention targets Rust programs, and by analyzing MIR as the core, it can deeply mine the semantic characteristics of Rust programs, detect Rust programs in multiple dimensions, and improve the detection efficiency and detection accuracy of Rust programs.
[0712] Device Embodiment
[0713] Reference Figure 2 , showing a structural block diagram of a program detection system according to the present invention. The program detection system includes a package manager, a static analyzer, and a vulnerability detector.
[0714] Among them, the package manager is used to parse the source code of the target program and determine the intermediate intermediate representation corresponding to the source code;
[0715] The static analyzer is used to analyze the intermediate intermediate representation, construct a control flow graph; perform fixed-point iteration analysis on the target program based on the control flow graph to determine the state data corresponding to each function in the target program, and integrate the state data into global data; the control flow graph is used to reflect the execution path and state changes of the target program;
[0716] The vulnerability detector is used to perform at least one of memory safety detection, concurrent safety detection, and numerical safety detection on the global data and generate a detection result.
[0717] Optionally, the package manager is specifically used for:
[0718] Identify according to the analysis options and set environment variables and compilation flags; among them, the environment variables are used to pass the analysis options specified by the user and indicate the top-level compilation unit to be analyzed; the compilation flags are used to indicate the compiler in the package manager to generate a complete intermediate intermediate representation;
[0719] Locate the source code of the target program according to the source code path and generate the intermediate intermediate representation corresponding to the target program.
[0720] Optionally, the package manager is further used for:
[0721] Construct a global context according to the analysis options; the global context is used to provide the basic environment required for analyzing the target program;
[0722] Initialize the static analyzer according to the global context to analyze the intermediate intermediate representation.
[0723] Optionally, the static analyzer is specifically used for:
[0724] Divide the source code into at least one basic block according to the intermediate intermediate representation, and respectively determine the control flow relationship between each basic block;
[0725] Taking the basic block as a node, draw a directed edge corresponding to the node according to the control flow relationship to obtain the control flow graph.
[0726] Optionally, the static analyzer is further used for:
[0727] In the case where there is a loop structure in the control flow graph, identify the target connected component in the control flow graph;
[0728] Based on the target connected component, decompose the control flow graph into at least one set of components; the components include a single basic block or a loop structure composed of at least one basic block;
[0729] Starting from the first component, traverse the control flow graph based on the depth - first search algorithm and update the corresponding sorting information according to a preset sorting strategy;
[0730] According to the updated sorting information, generate a sorting result corresponding to the at least one component; the sorting result is used to indicate the analysis order corresponding to the at least one component during the fixed - point algorithm analysis of the target program.
[0731] Optionally, the static analyzer is specifically configured to:
[0732] Extract the instructions in each basic block corresponding to the target program based on the control flow graph;
[0733] According to the instructions in the basic block, determine whether the basic block contains only numerical operations;
[0734] In the case where the basic block contains only numerical operations, update the numerical domain according to the value ranges and inequality relationships of the variables in the basic block; the numerical domain is used to record the numerical information of the variables in the target program;
[0735] Otherwise, update the symbol domain and map the constraint conditions corresponding to the symbol information in the symbol domain to the numerical domain; the symbol domain is used to manage the symbol information in the target program.
[0736] Optionally, the static analyzer is further configured to:
[0737] When performing fixed - point iteration analysis on the loop structure in the target program, if the iteration times of at least one first variable in the loop structure are greater than a preset threshold, expand the value range corresponding to the first variable to the global top element;
[0738] After the first variable reaches an initial fixed point, perform a shrinking operation on the value range of the first variable according to the value corresponding to the fixed point.
[0739] Optionally, the vulnerability detector includes a memory safety detector, a concurrency safety detector, and a numerical safety detector;
[0740] The memory safety detector is used to perform path analysis on the target program using the global data to identify the memory access paths in the target program; perform symbolic analysis on the target program based on the memory access paths, track the ownership transfer and insecure calls corresponding to the target program, and generate a memory safety detection result;
[0741] The concurrency safety detector is used to analyze the lock usage in the target program and construct a lock dependency graph; based on the global data and the lock dependency graph, detect potential concurrency safety issues in the target program and generate a concurrency safety detection result;
[0742] The numerical safety detector is used to respectively determine the value ranges corresponding to each variable in the target program using the global data and construct a linear constraint system; detect potential numerical safety issues in the target program according to the linear constraint system and generate a numerical safety detection result; wherein, the linear constraint system is used to describe the mutual relationship and operation conditions between variables.
[0743] Optionally, the memory safety detector is specifically used for:
[0744] Based on the memory access paths, track the sources and destinations of the pointers related to memory allocation in the target program, and update the mapping relationship between the pointers and the memory blocks;
[0745] Simulate the symbolic execution process in the target program according to the mapping relationship, construct the symbolic state of the target program, update the abstract domain and mark the target call operations;
[0746] In the case of detecting an insecure operation related to the target call operation, generate detection information corresponding to the target call operation;
[0747] Track the memory allocation and release operations in the target program according to the detection information and detect the legality of the memory release operations.
[0748] Optionally, the concurrency safety detector is specifically used for:
[0749] Extract the operations related to locks from the target program and respectively obtain the execution paths of each thread for the locks;
[0750] Construct the lock dependency graph corresponding to the target program according to the execution paths of each thread for the locks; the lock dependency graph is used to reflect the order of lock acquisition and release by each thread.
[0751] Optionally, the concurrency safety detector is specifically used for:
[0752] Use the depth - first search algorithm to detect the lock - dependency graph and determine whether there is a potential deadlock in the target program;
[0753] Analyze the usage of condition variables in the target program and detect whether there is a race condition or deadlock in the target program according to the usage;
[0754] Perform atomic operation analysis on the target program. According to the lock - dependency graph and the usage of atomic operations, detect whether the access of each thread in the target program to atomic variables is normal in a concurrent environment;
[0755] Analyze the access paths corresponding to shared variables in the target program. According to the lock - dependency graph and the access paths, detect whether there is concurrent access to the shared variables by each thread in the target program.
[0756] Optionally, the concurrent safety detector is specifically configured to:
[0757] In the case where a loop is detected in the lock - dependency graph, mark the loop as a potential deadlock;
[0758] Generate a first warning message according to the acquisition and release order of the locks corresponding to the loop and the corresponding thread calls.
[0759] Optionally, the concurrent safety detector is specifically configured to:
[0760] When a first thread performs a predetermined wait or wake - up operation on a first condition variable in the target program, record the dependency of the first thread on the first condition variable in the lock - dependency graph and track whether the lock held by the first thread is correctly released;
[0761] When the target program performs a predetermined notification operation, determine whether the awakened second thread can reacquire the lock and execute safely;
[0762] When there is at least one condition variable wait in the target program accompanied by lock acquisition and release operations, detect the conditional dependencies and lock - holding situations among threads in the lock - dependency graph and capture potential deadlock problems.
[0763] Optionally, the numerical safety detector is specifically configured to:
[0764] Assign an initial value range to each variable in the target program;
[0765] During the process of traversing each basic block in the target program, adjust the value range of variables according to arithmetic instructions and branch conditions;
[0766] Converting the operation conditions corresponding to the comparison instructions or arithmetic instructions defined in the target program into linear inequalities;
[0767] A linear constraint system is constructed according to the value ranges of the variables and the linear inequalities.
[0768] Optionally, the numerical safety detector is specifically used for:
[0769] Solving the linear constraint system to determine a first value range of arithmetic operands and a second value range of arithmetic results corresponding to each arithmetic instruction in the target program;
[0770] Analyzing whether the first value interval and the second value interval fall within a legal range;
[0771] When the first value interval or the second value interval exceeds a legal range, it is determined that a numerical security problem exists in the target program and the problem is recorded.
[0772] In summary, an embodiment of the present invention provides a program detection system, which performs static analysis with the intermediate intermediate representation (MIR) of the Rust compiler as the core. Specifically, the source code of the target program is first parsed based on the package manager to generate MIR, and the MIR is analyzed to build a control flow graph. The target program is subjected to fixed-point iteration analysis based on the control flow graph, and the type and life cycle information at the MIR level are deeply mined to determine the state data corresponding to each function in the target program, and the state data is integrated into global data; at least one of memory safety detection, concurrency safety detection and numerical safety detection is performed on the global data, and a detection result is generated. The embodiment of the present invention is aimed at Rust programs, and by analyzing MIR as the core, it can deeply mine the semantic characteristics of Rust programs, detect Rust programs in multiple dimensions, and improve the detection efficiency and detection accuracy of Rust programs.
[0773] As for the device embodiment, since it is basically similar to the method embodiment, the description is relatively simple, and the relevant parts can be referred to the partial description of the method embodiment.
[0774] The various embodiments in this specification are described in a progressive manner, and each embodiment focuses on the differences from other embodiments. The same or similar parts between the various embodiments can be referenced to each other.
[0775] Regarding the device in the above embodiment, the specific manner in which each module performs operations has been described in detail in the embodiment of the method, and will not be elaborated here.
[0776] Figure 4 FIG. 0 is a block diagram of an electronic device 600 for program detection according to an exemplary embodiment. For example, the electronic device 600 may be a mobile phone, a computer, a digital broadcast terminal, a messaging device, a game console, a tablet device, a medical device, a fitness device, a personal digital assistant, etc.
[0777] Referring Figure 4 , the electronic device 600 may include one or more of the following components: a processing component 602, a memory 604, a power component 606, a multimedia component 608, an audio component 610, an input / output (I / O) interface 612, a sensor component 614, and a communication component 616.
[0778] The processing component 602 generally controls the overall operation of the electronic device 600, such as operations associated with display, telephone calls, data communications, camera operations, and recording operations. The processing element 602 may include one or more processors 620 to execute instructions to complete all or part of the steps of the above methods. In addition, the processing component 602 may include one or more modules to facilitate the interaction between the processing component 602 and other components. For example, the processing component 602 may include a multimedia module to facilitate the interaction between the multimedia component 608 and the processing component 602.
[0779] The memory 604 is configured to store various types of data to support the operation of the electronic device 600. Examples of such data include instructions for any application or method operating on the electronic device 600, contact data, phone book data, messages, pictures, videos, etc. The memory 604 may be implemented by any type of volatile or non-volatile storage device or a combination thereof, such as static random access memory (SRAM), electrically erasable programmable read-only memory (EEPROM), erasable programmable read-only memory (EPROM), programmable read-only memory (PROM), read-only memory (ROM), magnetic memory, flash memory, a magnetic disk, or an optical disk.
[0780] The power component 606 provides power to various components of the electronic device 600. The power component 606 may include a power management system, one or more power supplies, and other components associated with generating, managing, and distributing power for the electronic device 600.
[0781] The multimedia component 608 includes a screen that provides an output interface between the electronic device 600 and the user.
[0782] The audio component 610 is configured to output and / or input audio signals. For example, the audio component 610 includes a microphone (MIC), which is configured to receive external audio signals when the electronic device 600 is in an operation mode, such as a call mode, a recording mode, and a voice message processing mode. The received audio signals can be further stored in the memory 604 or transmitted via the communication component 616. In some embodiments, the audio component 610 further includes a speaker for outputting audio signals.
[0783] The I / O interface 612 provides an interface between the processing component 602 and a peripheral interface module, and the peripheral interface module can be a keyboard, a click wheel, buttons, etc. These buttons can include, but are not limited to: a home button, a volume button, a start button, and a lock button.
[0784] The sensor component 614 includes one or more sensors for providing status assessments of various aspects of the electronic device 600. In some embodiments, the sensor component 614 can further include an acceleration sensor, a gyroscope sensor, a magnetic sensor, a pressure sensor, or a temperature sensor.
[0785] The communication component 616 is configured to facilitate communication between the electronic device 600 and other devices in a wired or wireless manner. The electronic device 600 can access a wireless network based on a communication standard, such as WiFi, 2G, or 3G, or a combination thereof. In an exemplary embodiment, the communication component 616 receives a broadcast signal or broadcast-related information from an external broadcast management system via a broadcast channel.
[0786] In an exemplary embodiment, the electronic device 600 can be implemented by one or more application specific integrated circuits (ASICs), digital signal processors (DSPs), digital signal processing devices (DSPDs), programmable logic devices (PLDs), field programmable gate arrays (FPGAs), controllers, microcontrollers, microprocessors, or other electronic components for performing the above method.
[0787] In an exemplary embodiment, a non-transitory computer-readable storage medium including instructions is also provided, such as the memory 604 including instructions, and the instructions can be executed by the processor 620 of the electronic device 600 to complete the above method. For example, the non-transitory computer-readable storage medium can be a ROM, a random access memory (RAM), a CD-ROM, a magnetic tape, a floppy disk, and an optical data storage device, etc.
[0788] A non-transitory computer-readable storage medium, when the instructions in the storage medium are executed by the processor of an electronic device (server or terminal), enables the processor to execute Figure 1 the method shown.
[0789] The above has introduced in detail a program detection method, system and electronic device provided by the present invention. Specific examples are used in this article to elaborate on the principle and implementation manner of the present invention. The description of the above embodiments is only used to help understand the method and its core idea of the present invention; at the same time, for those of ordinary skill in the art, according to the idea of the present invention, there will be changes in the specific implementation manner and application scope. In summary, the content of this specification should not be construed as a limitation to the present invention.< / domaintype> < / domaintype> < / domaintype> < / domaintype> < / domaintype> < / domaintype>
Claims
1. A program detection method, characterized in that, The method includes: Parsing the source code of the target program based on a package manager to determine the intermediate intermediate representation corresponding to the source code; Analyzing the intermediate intermediate representation to construct a control flow graph; the control flow graph is used to reflect the execution path and state changes of the target program; Performing fixed-point iterative analysis on the target program based on the control flow graph to determine the state data corresponding to each function in the target program, and integrating the state data into global data; Performing at least one of memory safety detection, concurrent safety detection, and numerical safety detection on the global data, and generating a detection result; Wherein, the memory safety detection is used to track the transfer of ownership of memory blocks and unsafe calls, and locate the risk of lifecycle damage; the concurrent safety detection is used to analyze resource competition or lock order conflicts between threads, and identify the critical path leading to concurrent conflicts; the numerical safety detection is used to determine the range of each integer variable and arithmetic overflow in the target program, and capture the root cause of potential overflow and numerical overflow.
2. The method according to claim 1, wherein The parsing the source code of the target program based on a package manager to determine the intermediate intermediate representation corresponding to the source code includes: Analyzing the command-line parameters input by the user to determine the analysis options and source code path specified by the user, and loading them into the package manager; wherein, the analysis options include analyzer configuration parameters; The package manager identifies according to the analysis options, and sets environment variables and compilation flags; wherein, the compilation flags are used to instruct the compiler in the package manager to generate a complete intermediate intermediate representation; The package manager locates the source code of the target program according to the source code path, and generates the intermediate intermediate representation corresponding to the target program.
3. The method according to claim 2, wherein The method further includes: Constructing a global context according to the analysis options; the global context is used to provide the basic environment required for analyzing the target program; Initializing a static analyzer according to the global context to analyze the intermediate intermediate representation.
4. The method according to claim 1, wherein The analyzing the intermediate intermediate representation to construct a control flow graph includes: Dividing the source code into at least one basic block according to the intermediate intermediate representation, and respectively determining the control flow relationship between each basic block; Taking the basic block as a node, and drawing a directed edge corresponding to the node according to the control flow relationship to obtain the control flow graph.
5. The method according to claim 1 or 4, characterized in that, The method further includes: When there is a loop structure in the control flow graph, identifying the target connected component in the control flow graph; Decomposing the control flow graph into at least one group of components based on the target connected component; Starting from the first component, traversing the control flow graph based on the depth-first search algorithm, and updating the corresponding sorting information according to a preset sorting strategy; Generating a sorting result corresponding to the at least one component according to the updated sorting information.
6. The method according to claim 1, wherein The determining the state data corresponding to each function in the target program, and integrating the state data into global data includes: Extracting the instructions in each basic block corresponding to the target program respectively based on the control flow graph; According to the instructions in the basic block, determine whether the basic block only contains numerical operations; In the case that the basic block only contains numerical operations, update the numerical domain according to the value ranges and inequality relationships of the variables in the basic block; Otherwise, update the symbolic domain and map the constraint conditions corresponding to the symbolic information in the symbolic domain to the numerical domain.
7. The method according to claim 1, characterized in that, Perform at least one of memory safety detection, concurrent safety detection, and numerical safety detection on the global data and generate a detection result, including at least one of the following: Use the global data to perform path analysis on the target program, identify the memory access paths in the target program, perform symbolic analysis on the target program based on the memory access paths, trace the ownership transfer and unsafe calls corresponding to the target program, and generate a memory safety detection result; Analyze the lock usage in the target program and construct a lock dependency graph. Based on the global data and the lock dependency graph, detect potential concurrent safety issues in the target program and generate a concurrent safety detection result; Use the global data to respectively determine the value ranges corresponding to each variable in the target program, construct a linear constraint system, and detect potential numerical safety issues in the target program according to the linear constraint system to generate a numerical safety detection result.
8. The method according to claim 7, wherein The symbolic analysis of the target program based on the memory access path, tracing the ownership transfer and unsafe calls corresponding to the target program, and generating a memory safety detection result includes: Based on the memory access path, trace the sources and destinations of the pointers related to memory allocation in the target program and update the mapping relationship between the pointers and the memory blocks; Simulate the symbolic execution process in the target program according to the mapping relationship, construct the symbolic state of the target program, update the abstract domain and mark the target call operation; In the case of detecting an unsafe operation related to the target call operation, generate the detection information corresponding to the target call operation; Trace the memory allocation and release operations in the target program according to the detection information and detect the legality of the memory release operation.
9. The method according to claim 7, wherein The analysis of the lock usage in the target program and the construction of the lock dependency graph include: Extract the operations related to locks from the target program and respectively obtain the execution paths of each thread for the locks; Construct the lock dependency graph corresponding to the target program according to the execution paths of each thread for the locks; the lock dependency graph is used to reflect the order of lock acquisition and release by each thread.
10. The method according to claim 7, wherein The detection of potential concurrent safety issues in the target program based on the global data and the lock dependency graph includes: Use the depth-first search algorithm to detect the lock dependency graph to determine whether there is a potential deadlock in the target program; Analyze the usage of condition variables in the target program and detect whether there is a condition race or deadlock in the target program according to the usage; Perform atomic operation analysis on the target program. According to the lock dependency graph and the usage of atomic operations, detect whether the access of each thread in the target program to atomic variables is normal in a concurrent environment; Analyze the access paths corresponding to the shared variables in the target program, and based on the lock dependency graph and the access paths, detect whether there are concurrent accesses to the shared variables by each thread in the target program.
11. The method according to claim 10, wherein The determination of whether there is a potential deadlock in the target program includes: In the case where a loop is detected in the lock dependency graph, mark the loop as a potential deadlock; Generate a first warning message according to the acquisition and release order of the locks corresponding to the loop and the corresponding thread calls.
12. The method according to claim 10, wherein The detection of whether there is a race condition or deadlock in the target program according to the usage situation includes: When a first thread performs a predefined wait or wake-up operation on a first conditional variable in the target program, record the dependency of the first thread on the first conditional variable in the lock dependency graph, and track whether the lock held by the first thread is correctly released; When a predefined notification operation is executed in the target program, determine whether the awakened second thread can reacquire the lock and execute safely; When there is at least one conditional variable wait in the target program accompanied by lock acquisition and release operations, detect the conditional dependencies and lock holding situations among the threads in the lock dependency graph to capture potential deadlock problems.
13. The method according to claim 7, wherein The use of the global data to respectively determine the value ranges corresponding to each variable in the target program and construct a linear constraint system includes: Through a numerical safety detector, assign an initial value range to each variable in the target program; During the traversal of each basic block in the target program, adjust the value ranges of the variables according to arithmetic instructions and branch conditions; Convert the operation conditions corresponding to the predefined comparison instructions or arithmetic instructions in the target program into linear inequalities; Construct a linear constraint system according to the value ranges of the variables and the linear inequalities.
14. A program detection system, characterized in that, The program detection system includes a package manager, a static analyzer, and a vulnerability detector; The package manager is used to parse the source code of the target program to determine the intermediate intermediate representation corresponding to the source code; The static analyzer is used to analyze the intermediate intermediate representation to construct a control flow graph; Based on the control flow graph, perform fixed-point iteration analysis on the target program to determine the state data corresponding to each function in the target program, and integrate the state data into global data; The vulnerability detector is used to perform at least one of memory safety detection, concurrent safety detection, and numerical safety detection on the global data and generate a detection result; Among them, the memory safety detection is used to track the ownership transfer and unsafe calls of memory blocks to locate the risk of lifecycle destruction; the concurrent safety detection is used to analyze resource competition or lock order conflicts among threads to identify the critical path leading to concurrent conflicts; the numerical safety detection is used to determine the range of each integer variable in the target program and arithmetic overflow, and capture the root cause of potential overflow and numerical out-of-bounds.
15. An electronic device, characterized in that, The electronic device includes a memory and one or more programs, where the one or more programs are stored in the memory and are configured to be executed by one or more processors to perform the program detection method according to any one of claims 1 to 13.
16. A readable storage medium, characterized in that, When the instructions in the storage medium are executed by the processor of the electronic device, the processor is enabled to perform the program detection method according to any one of claims 1 to 13.
Citation Information
Patent Citations
Cross-chip platform compiling tool chain method
CN119322619A
Vulnerability reachable path detection method and device combining SCA with SAST
CN119337386A