CN116710894A - 函数调用上下文的编码、解码方法及装置 - Google Patents

函数调用上下文的编码、解码方法及装置 Download PDF

Info

Publication number
CN116710894A
CN116710894A CN202180088006.7A CN202180088006A CN116710894A CN 116710894 A CN116710894 A CN 116710894A CN 202180088006 A CN202180088006 A CN 202180088006A CN 116710894 A CN116710894 A CN 116710894A
Authority
CN
China
Prior art keywords
function
thread
context
call
belongs
Prior art date
Legal status (The legal status is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the status listed.)
Pending
Application number
CN202180088006.7A
Other languages
English (en)
Inventor
周卿
张汝涛
Current Assignee (The listed assignees may be inaccurate. Google has not performed a legal analysis and makes no representation or warranty as to the accuracy of the list.)
Huawei Technologies Co Ltd
Original Assignee
Huawei Technologies Co Ltd
Priority date (The priority date is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the date listed.)
Filing date
Publication date
Application filed by Huawei Technologies Co Ltd filed Critical Huawei Technologies Co Ltd
Publication of CN116710894A publication Critical patent/CN116710894A/zh
Pending legal-status Critical Current

Links

Classifications

    • GPHYSICS
    • G06COMPUTING; CALCULATING OR COUNTING
    • G06FELECTRIC DIGITAL DATA PROCESSING
    • G06F9/00Arrangements for program control, e.g. control units
    • G06F9/06Arrangements for program control, e.g. control units using stored programs, i.e. using an internal store of processing equipment to receive or retain programs
    • G06F9/46Multiprogramming arrangements
    • G06F9/461Saving or restoring of program or task context
    • GPHYSICS
    • G06COMPUTING; CALCULATING OR COUNTING
    • G06FELECTRIC DIGITAL DATA PROCESSING
    • G06F9/00Arrangements for program control, e.g. control units
    • G06F9/06Arrangements for program control, e.g. control units using stored programs, i.e. using an internal store of processing equipment to receive or retain programs
    • G06F9/44Arrangements for executing specific programs
    • G06F9/448Execution paradigms, e.g. implementations of programming paradigms
    • G06F9/4482Procedural
    • G06F9/4484Executing subprograms
    • GPHYSICS
    • G06COMPUTING; CALCULATING OR COUNTING
    • G06FELECTRIC DIGITAL DATA PROCESSING
    • G06F9/00Arrangements for program control, e.g. control units
    • G06F9/06Arrangements for program control, e.g. control units using stored programs, i.e. using an internal store of processing equipment to receive or retain programs
    • G06F9/30Arrangements for executing machine instructions, e.g. instruction decode
    • G06F9/30145Instruction analysis, e.g. decoding, instruction word fields
    • G06F9/3016Decoding the operand specifier, e.g. specifier format

Landscapes

  • Engineering & Computer Science (AREA)
  • Software Systems (AREA)
  • Theoretical Computer Science (AREA)
  • Physics & Mathematics (AREA)
  • General Engineering & Computer Science (AREA)
  • General Physics & Mathematics (AREA)
  • Compression, Expansion, Code Conversion, And Decoders (AREA)
  • Stored Programmes (AREA)
  • Devices For Executing Special Programs (AREA)

Abstract

提供了一种函数的调用上下文的编码方法、解码方法及装置。编码方法包括:获取程序代码中的多个线程之间的创建关系对应的编码值,进而根据多个线程之间的创建关系对应的编码值和目标函数的调用上下文信息得到目标函数所属的线程的上下文的编码结果。编码方法能够得到目标函数所属的线程的上下文的编码结果,区分多线程中的函数的不同调用上下文,有利于提高分析效率和分析精度。

Description

函数调用上下文的编码、解码方法及装置 技术领域
本申请涉及编程领域,具体涉及一种函数的调用上下文的编码方法、解码方法及装置。
背景技术
一个函数被多次调用时会有不同的调用上下文,例如,每次被调用时的参数不同。函数的调用上下文(calling context)对程序分析、调试以及事件日志等多种应用而言至关重要。以程序分析为例,相较于不区分一个函数的不同的调用上下文,区分一个函数的不同的调用上下文能够显著提高分析结果的精度。
通过函数调用链(call string)能够区分一个函数的不同调用上下文。函数调用链用于指示函数调用的路径。对于源码中的任一个函数,函数调用的路径能够唯一表达该函数的调用上下文信息。然而,函数调用链具有很高的空间开销,当函数调用链本身过长时,存储该函数调用链需要很大的存储开销。函数调用上下文编码(calling context encoding)通过对函数调用链进行编码,以减少存储开销。然而,该方案得到的编码结果无法区分多线程中的函数调用上下文。对于给定的函数调用链的编码,需要通过解码还原得到函数调用链,进而根据函数调用链得到给定的函数调用上下文所在的线程信息。若通过反复解码以得到函数调用上下文所在的线程信息,则会导致较大的分析时间开销,影响分析效率。
因此,如何区分多线程中的函数的不同调用上下文成为一个亟待解决的问题。
发明内容
本申请提供一种函数的调用上下文的编码方法、解码方法及装置,能够区分多线程中的函数的不同调用上下文,有利于提高分析效率和分析精度。
第一方面,提供了一种函数的调用上下文的编码方法,该方法包括:获取目标函数的调用上下文信息;获取程序代码中的多个线程之间的创建关系对应的编码值,程序代码包括目标函数;根据目标函数的调用上下文信息和多个线程之间的创建关系对应的编码值对目标函数所属的线程的上下文进行编码,得到目标函数所属的线程的上下文的编码结果。
根据本申请实施例的方案,通过对函数所属的线程的上下文进行编码,编码结果能够指示函数所属的线程的上下文,进而能够区分多线程中的函数的不同调用上下文,有利于提高分析精度。此外,本申请实施例的方案无需对编码结果进行解码即可得到函数所属的线程的信息,能够快速区分函数所属的线程的上下文,节省了解码带来的时间开销,有利于提高分析效率。此外,通过对函数所属的线程的上下文进行编码,空间开销较小,能够有效减少存储线程的上下文信息所导致的存储空间的压力。本申请实施例的方案能够在不大量占用存储空间的情况下,区分函数所属的线程的上下文,提高分析精度和分析效率。
目标函数的调用上下文指的是目标函数被调用的路径。目标函数的调用上下文也可以理解为目标函数的调用路径,目标函数是基于该调用路径被其他函数调用的。示例性地, 该调用路径的起点可以为程序代码中的根函数。
目标函数的调用上下文信息用于指示目标函数的调用上下文。或者说,目标函数的调用上下文信息用于指示目标函数的调用路径(call path)。目标函数所属的线程指的是目标函数的调用上下文所属的线程。
线程的上下文指的是该线程被创建的过程。线程的上下文也可以理解为线程的创建路径。
程序代码中的多个线程之间的创建关系对应的编码值是通过对程序代码中的多个线程之间的创建关系进行编码得到的。
线程之间的创建关系可以由线程之间的线程创建指令指示。
程序代码中的多个线程之间的创建关系对应的编码值可以是预先设置的。
程序代码中的多个线程之间的创建关系对应的编码值可以通过数字表示,例如,程序代码中的多个线程之间的创建关系对应的编码值为整数。
在程序代码中的多个线程中的任两个线程之间存在多个创建关系的情况下,该多个创建关系对应的编码值不同。
示例性地,程序代码中的多个线程之间的创建关系对应的编码值可以通过线程调用上下文编码图(thread calling context encoding graph,TEG)表示。TEG中包括多个线程节点以及多个线程节点之间的边,还包括边上的编码值。TEG中的线程节点用于表示程序代码中的线程,多个线程节点之间的边用于表示多个线程之间的创建关系,边上的编码值即为线程之间的创建关系对应的编码值。
结合第一方面,在第一方面的某些实现方式中,程序代码中的多个线程之间的创建关系对应的编码值是利用调用上下文编码算法对程序代码中的多个线程之间的创建关系进行编码得到的。
具体地,TEG是通过调用上下文编码算法对线程关系图(thread graph,TG)进行编码得到的。TG用于表示多个线程之间的创建关系。TG包括多个线程节点以及多个线程节点之间的边。TG中的线程节点用于表示程序代码中的线程,多个线程节点之间的边用于表示多个线程之间的创建关系。
根据本申请实施例的方案,通过调用上下文编码算法对多个线程之间的创建关系进行编码,能够保证线程的不同上下文的编码结果不同,使得线程的上下文的编码结果唯一指示线程的上下文。
结合第一方面,在第一方面的某些实现方式中,程序代码中的多个线程包括父线程和子线程,父线程中的线程创建函数用于创建子线程,父线程和子线程之间的创建关系对应的编码值与父线程中的线程创建函数的函数调用上下文对应。
可选地,父线程和子线程之间的创建关系对应的编码值与父线程中的线程创建函数的函数调用上下文的编码结果对应。
根据本申请实施例的方案,这样能够保证对编码结果进行解码后能够得到完整的函数调用链,不会丢失函数在其他线程中的调用上下文。
结合第一方面,在第一方面的某些实现方式中,目标函数所属的线程的上下文的编码结果用于指示目标函数所属的线程中的线程入口函数和目标函数所属的线程的上下文的编码值。
根据本申请实施例的方案,通过线程入口函数即可区分目标函数的调用上下文所属的线程,有利于快速区分不同线程中的函数的调用上下文,通过线程的上下文的编码值和线程入口函数即可唯一指示该线程的上下文,进一步准确区分线程的不同的上下文,有利于提高分析结果的准确性。
结合第一方面,在第一方面的某些实现方式中,方法还包括:获取程序代码中的多个线程内的多个函数之间的调用关系对应的编码值;根据目标函数的调用上下文信息和程序代码中的多个线程内的多个函数之间的调用关系对应的编码值对目标函数在所属线程内的函数调用上下文进行编码,得到目标函数在所属线程内的函数调用上下文的编码结果。
线程内的函数包括该线程的线程入口函数以及线程入口函数的子函数。其中,线程入口函数的子函数指的是以该线程入口函数作为调用起点,在不跨越线程创建语句的情况下被调用的所有函数。
目标函数在所属线程内的函数调用上下文指的是目标函数在所属线程内被调用的路径。该调用路径的起点为目标函数所属线程的线程入口函数。
通过目标函数在所属线程内的函数调用上下文的编码结果和目标函数所属的线程的上下文的编码信息即可区分目标函数的调用上下文。
示例性地,多个线程内的多个函数之间的调用关系对应的编码值可以由线程内的函数调用上下文编码图(callcalling context encoding graph,CEG)表示。线程内的CEG中包括线程内的多个函数节点以及多个函数节点之间的边,还包括边上的编码值。线程内的CEG中的函数节点用于表示线程内的函数,多个函数节点之间的边用于表示多个函数之间的调用关系,边上的编码值即为线程内的函数之间的调用关系对应的编码值。
程序代码中的多个线程内的多个函数之间的调用关系对应的编码值是对多个线程内的多个函数之间的调用关系进行编码得到的。
程序代码中的多个线程内的多个函数之间的调用关系对应的编码值可以是预先设置的。
程序代码中的多个线程内的多个函数之间的调用关系对应的编码值可以通过数字表示,例如,程序代码中的多个线程内的多个函数之间的调用关系对应的编码值为整数。
结合第一方面,在第一方面的某些实现方式中,多个线程内的多个函数之间的调用关系对应的编码值是分别利用调用上下文编码算法对多个线程内的多个函数之间的调用关系进行编码得到的。
具体地,线程内的CEG是通过调用上下文编码算法对线程内的函数调用图(calling graph,CG)进行编码得到的。线程内的CG用于表示线程内的函数之间的调用关系。线程内的CG包括线程内的多个函数节点以及多个函数节点之间的边,还包括边上的编码值。线程内的CEG中的函数节点用于表示线程内的函数,多个函数节点之间的边用于表示多个函数之间的调用关系。
根据本申请实施例的方案,通过调用上下文编码算法对多个线程内的多个函数之间的调用关系进行编码,能够保证线程内的函数的不同的函数调用上下文的编码结果不同,使得线程内的函数的不同的函数调用上下文编码结果唯一指示线程内的函数的函数调用上下文。
结合第一方面,在第一方面的某些实现方式中,多个线程中的一个线程内的多个函数 之间的调用关系对应的编码值与多个函数之间的函数调用语句对应。
结合第一方面,在第一方面的某些实现方式中,目标函数在所属线程内的函数调用上下文的编码结果用于指示目标函数和目标函数在所属线程内的函数调用上下文的编码值。
结合第一方面,在第一方面的某些实现方式中,目标函数的调用上下文信息包括目标函数的函数调用链。
结合第一方面,在第一方面的某些实现方式中,根据目标函数的调用上下文信息和多个线程之间的创建关系对应的编码值对目标函数所属的线程的上下文进行编码,得到目标函数所属的线程的上下文的编码结果,包括:在函数调用链中包括线程创建函数所创建的线程入口函数的情况下,以函数调用链中的线程创建函数为分割点,将函数调用链分为至少两个子链,至少两个子链中的每个子链中的起始点为线程入口函数;根据多个线程内的多个函数之间的调用关系对应的编码值分别确定至少两个子链中的多个函数之间的调用关系对应的编码值;根据至少两个子链中的多个函数之间的调用关系对应的编码值分别确定至少两个子链中的线程创建函数在所属线程内的函数调用上下文对应的编码结果;根据至少两个子链中的线程创建函数在所属线程内的函数调用上下文对应的编码结果确定至少两个子链对应的线程之间的创建关系对应的编码值;将至少两个子链对应的线程之间的创建关系对应的编码值之和作为目标函数所属的线程的上下文的编码值;根据函数调用链中尾端的子链中的线程入口函数和目标函数所属的线程的上下文的编码值确定目标函数所属的线程的上下文的编码结果。
结合第一方面,在第一方面的某些实现方式中,目标函数的调用上下文信息包括目标函数的调用者函数的调用上下文的编码结果和第一指令,目标函数为调用者函数通过第一指令调用的函数,调用者函数的调用上下文的编码结果包括调用者函数所属的线程的上下文的编码结果和调用者函数在所属线程内的函数调用上下文的编码结果。
结合第一方面,在第一方面的某些实现方式中,根据目标函数的调用上下文信息和多个线程之间的创建关系对应的编码值对目标函数所属的线程的上下文进行编码,得到目标函数所属的线程的上下文的编码结果,包括:在第一指令为函数调用指令的情况下,将调用者函数所属的线程的上下文的编码结果作为目标函数所属的线程的上下文的编码结果;在第一指令为线程创建指令的情况下,根据调用者函数在所属线程内的函数调用上下文的编码结果确定调用者函数所属线程和目标函数所属线程之间的创建关系对应的编码值;将调用者函数所属的线程的上下文的编码值以及调用者函数所属线程和目标函数所属线程之间的创建关系对应的编码值之和作为目标函数所属的线程的上下文的编码值;根据目标函数和目标函数所属的线程的上下文的编码值确定目标函数所属的线程的上下文的编码结果。
结合第一方面,在第一方面的某些实现方式中,目标函数的上下文信息包括被目标函数调用的被调函数的调用上下文的编码结果,被调函数为目标函数调用的函数,被调函数的调用上下文的编码结果包括被调函数所属的线程的上下文的编码结果和被调函数在所属线程内的函数调用上下文的编码结果。
结合第一方面,在第一方面的某些实现方式中,目标函数的上下文信息包括被目标函数调用的被调函数的调用上下文的编码结果和第二指令,被调函数为目标函数通过第二指令调用的,被调函数的调用上下文的编码结果包括被调函数所属的线程的上下文的编码结 果和被调函数在所属线程内的函数调用上下文的编码结果。
结合第一方面,在第一方面的某些实现方式中,根据目标函数的调用上下文信息和多个线程之间的创建关系对应的编码值对目标函数所属的线程的上下文进行编码,得到目标函数所属的线程的上下文的编码结果,包括:在第二指令为函数调用指令的情况下,将被调函数所属的线程的上下文的编码结果作为目标函数所属的线程的上下文的编码结果;在第二指令为线程创建指令的情况下,根据被调函数所属的线程的上下文的编码结果确定目标函数所属线程和被调函数所属线程之间的创建关系对应的编码值;将被调函数所属的线程的上下文的编码值与目标函数所属线程和被调函数所属线程之间的创建关系对应的编码值之差作为目标函数所属的线程的上下文的编码值;根据目标函数所属线程的线程入口函数和目标函数所属的线程的上下文的编码值确定目标函数所属的线程的上下文的编码结果。
若被调函数所属线程的线程入口函数和被调函数不同,则第二指令为函数调用指令。若被调函数所属线程的线程入口函数和被调函数相同,也就是说,被调函数即为所属线程的线程入口函数,则第二指令为线程创建指令。也就是说,可以根据被调函数所属线程的线程入口函数和被调函数是否相同判断第二指令的类型。
结合第一方面,在第一方面的某些实现方式中,方法还包括:提供API,API的输入包括目标函数的调用上下文信息,API的输出包括目标函数所属的线程的上下文的编码结果。
结合第一方面,在第一方面的某些实现方式中,API的输出包括第一元素和第二元素,第一元素用于指示目标函数所属的线程中的线程入口函数,第二元素用于指示目标函数所属的线程的上下文编码值。
结合第一方面,在第一方面的某些实现方式中,API的输出包括第五元素,第五元素用于指示目标函数所属的线程中的线程入口函数和目标函数所属的线程的上下文编码值。
结合第一方面,在第一方面的某些实现方式中,API的输出还包括:目标函数在所属线程内的函数调用上下文的编码结果。
结合第一方面,在第一方面的某些实现方式中,API的输出包括第一元素、第二元素、第三元素和第四元素,第一元素用于指示目标函数所属的线程中的线程入口函数,第二元素用于指示目标函数所属的线程的上下文编码值,第三元素用于指示目标函数,第四元素用于指示目标函数在所属线程内的函数调用上下文的编码值。
结合第一方面,在第一方面的某些实现方式中,API的输出包括第五元素、第六元素和第七元素,第五元素用于指示目标函数所属的线程中的线程入口函数和目标函数所属的线程的上下文编码值,第六元素用于指示目标函数,第七元素用于指示目标函数在所属线程内的函数调用上下文的编码值。
第二方面,提供了一种函数的调用上下文的解码方法,该方法包括:获取目标函数的调用上下文的编码结果;获取程序代码中的多个线程之间的创建关系对应的编码值,程序代码包括目标函数;获取程序代码中的多个线程内的多个函数之间的调用关系对应的编码值;根据程序代码中的多个线程之间的创建关系对应的编码值和程序代码中的多个线程内的多个函数之间的调用关系对应的编码值对目标函数的调用上下文的编码结果进行解码,得到目标函数的函数调用链。
根据本申请实施例中的解码方法,可以与本申请实施例中的编码方法适配使用,由目标函数的调用上下文的编码结果得到目标函数的函数调用链,能够灵活转换目标函数的调用上下文的编码结果和函数调用链,有利于应用于多种分析场景中,兼容其他分析方法。
结合第二方面,在第二方面的某些实现方式中,程序代码中的多个线程包括父线程和子线程,父线程中的线程创建函数用于创建子线程,父线程和子线程之间的创建关系对应的编码值与父线程中的线程创建函数的函数调用上下文对应。
结合第二方面,在第二方面的某些实现方式中,目标函数的调用上下文的编码结果包括目标函数所属的线程的上下文的编码结果和目标函数在所属线程内的函数调用上下文的编码结果,目标函数所属的线程的上下文的编码结果用于指示目标函数所属的线程中的线程入口函数和目标函数所属的线程的上下文的编码值;目标函数在所属线程内的函数调用上下文的编码结果用于指示目标函数和目标函数在所属线程内的函数调用上下文的编码值。
结合第二方面,在第二方面的某些实现方式中,根据程序代码中的多个线程之间的创建关系对应的编码值和程序代码中的多个线程内的多个函数之间的调用关系对应的编码值对目标函数的调用上下文的编码结果进行解码,得到目标函数的函数调用链,包括:根据程序代码中的多个线程之间的创建关系对应的编码值对目标函数所属的线程的上下文的编码结果进行解码,得到目标函数所属的线程的上下文中的多个线程之间的创建关系对应的编码值,其中,目标函数所属的线程的上下文中的多个线程之间的创建关系对应的编码值之和等于目标函数所属的线程的上下文的编码值,目标函数所属的线程是根据目标函数所属的线程中的线程入口函数确定的;根据目标函数所属的线程的上下文中的多个线程之间的创建关系对应的编码值确定目标函数所属的线程的上下文中的多个线程中的线程创建函数的函数调用上下文的编码结果;根据程序代码中的多个线程内的多个函数之间的调用关系对应的编码值对目标函数所属的线程的上下文中的多个线程中的线程创建函数的函数调用上下文的编码结果进行解码,得到线程创建函数在所属线程内的函数调用链,其中,线程创建函数在所属线程内的函数调用链的调用起点为线程创建函数所属的线程的线程入口函数,线程创建函数在所属线程内的函数调用链的调用终点为线程创建函数,线程创建函数在所属线程内的函数调用链中的多个函数之间的调用关系对应的编码值之和等于线程创建函数在所属线程内的函数调用链的编码值;根据程序代码中的多个线程内的多个函数之间的调用关系对应的编码值对目标函数在所属线程内的函数调用上下文的编码结果进行解码,得到目标函数在所属线程内的函数调用链,其中,目标函数在所属线程内的函数调用链的调用起点为目标函数所属的线程的线程入口函数,目标函数在所属线程内的函数调用链的调用终点为目标函数,在目标函数在所属线程内的函数调用链的调用起点与目标函数在所属线程内的函数调用链的调用终点不同的情况下,目标函数在所属线程内的函数调用链中的多个函数之间的调用关系对应的编码值之和等于目标函数在所属线程内的函数调用上下文的编码值;根据线程创建函数在所属线程内的函数调用链和目标函数在所属线程内的函数调用链确定目标函数的函数调用链。
结合第二方面,在第二方面的某些实现方式中,方法还包括:提供API,API的输入包括目标函数的调用上下文的编码结果,API的输出包括目标函数的函数调用链。
结合第二方面,在第二方面的某些实现方式中,API的输入包括第一元素、第二元素、 第三元素和第四元素,第一元素用于指示目标函数所属的线程中的线程入口函数,第二元素用于指示目标函数所属的线程的上下文编码值,第三元素用于指示目标函数,第四元素用于指示目标函数在所属线程内的函数调用上下文的编码值。
结合第二方面,在第二方面的某些实现方式中,API的输入包括第五元素、第六元素和第七元素,第五元素用于指示目标函数所属的线程中的线程入口函数和目标函数所属的线程的上下文编码值,第六元素用于指示目标函数,第七元素用于指示目标函数在所属线程内的函数调用上下文的编码值。
第三方面,提供了一种函数的调用上下文的编码方法,该方法包括提供API,该API的输入包括目标函数的调用上下文信息,API的输出包括目标函数目标函数的调用上下文的编码结果,其中,编码结果是根据第一方面以及第一方面中的任意一种实现方式中的方法得到的。
结合第三方面,在第三方面的某些实现方式中,API的输出包括第一元素、第二元素、第三元素和第四元素,第一元素用于指示目标函数所属的线程中的线程入口函数,第二元素用于指示目标函数所属的线程的上下文编码值,第三元素用于指示目标函数,第四元素用于指示目标函数在所属线程内的函数调用上下文的编码值。
结合第三方面,在第三方面的某些实现方式中,API的输出包括第五元素、第六元素和第七元素,第五元素用于指示目标函数所属的线程中的线程入口函数和目标函数所属的线程的上下文编码值,第六元素用于指示目标函数,第七元素用于指示目标函数在所属线程内的函数调用上下文的编码值。
第四方面,提供了一种调用API的方法,该方法包括:调用API,该API的输入包括目标函数的调用上下文信息,API的输出包括目标函数目标函数的调用上下文的编码结果,其中,编码结果是根据第一方面以及第一方面中的任意一种实现方式中的方法得到的。结合第四方面,在第四方面的某些实现方式中,API的输出包括第一元素、第二元素、第三元素和第四元素,第一元素用于指示目标函数所属的线程中的线程入口函数,第二元素用于指示目标函数所属的线程的上下文编码值,第三元素用于指示目标函数,第四元素用于指示目标函数在所属线程内的函数调用上下文的编码值。
结合第四方面,在第四方面的某些实现方式中,API的输出包括第五元素、第六元素和第七元素,第五元素用于指示目标函数所属的线程中的线程入口函数和目标函数所属的线程的上下文编码值,第六元素用于指示目标函数,第七元素用于指示目标函数在所属线程内的函数调用上下文的编码值。
第五方面,提供了一种函数调用上下文的编码装置,装置包括用于执行上述第一方面以及第一方面中的任意一种实现方式中的方法的模块或单元。
第六方面,提供了一种函数调用上下文的解码装置,装置包括用于执行上述第二方面以及第二方面中的任意一种实现方式中的方法的模块或单元。
应理解,在上述第一方面中对相关内容的扩展、限定、解释和说明也适用于第二方面、第三方面、第四方面、第五方面和第六方面中相同的内容。
第七方面,提供了一种函数调用上下文的编码装置,该装置包括:存储器,用于存储程序;处理器,用于执行存储器存储的程序,当存储器存储的程序被执行时,处理器用于执行上述第一方面以及第一方面中的任意一种实现方式中的方法。
第八方面,提供了一种函数调用上下文的解码装置,该装置包括:存储器,用于存储程序;处理器,用于执行存储器存储的程序,当存储器存储的程序被执行时,处理器用于执行上述第二方面以及第二方面中的任意一种实现方式中的方法。
第九方面,提供一种计算机可读介质,该计算机可读介质存储用于设备执行的程序代码,该程序代码包括用于执行上述各方面中的任意一种实现方式中的方法。
第十方面,提供一种包含指令的计算机程序产品,当该计算机程序产品在计算机上运行时,使得计算机执行上述各方面中的任意一种实现方式中的方法。
第十一方面,提供一种芯片,所述芯片包括处理器与数据接口,所述处理器通过所述数据接口读取存储器上存储的指令,执行上述各方面中的任意一种实现方式中的方法。
可选地,作为一种实现方式,所述芯片还可以包括存储器,所述存储器中存储有指令,所述处理器用于执行所述存储器上存储的指令,当所述指令被执行时,所述处理器用于执行上述各方面中的任意一种实现方式中的方法。
上述芯片具体可以是现场可编程门阵列(field-programmable gate array,FPGA)或者专用集成电路(application-specific integrated circuit,ASIC)。
附图说明
图1是本申请实施例提供的一种静态程序分析的示意性流程图;
图2是一种函数调用链的示意图;
图3是一种函数调用上下文编码的示意图;
图4是本申请实施例提供的一种应用场景的示意图;
图5是本申请实施例提供的一种静态程序分析器的示意性框图;
图6是本申请实施例提供的一种函数的调用上下文的编码方法的示意性流程图;
图7是本申请实施例提供的一种函数调用图;
图8是本申请实施例提供的一种线程关系图;
图9是本申请实施例提供的一种线程内的函数调用图;
图10是本申请实施例提供的一种线程内的函数调用上下文编码图;
图11是本申请实施例提供的一种线程调用上下文编码图;
图12是本申请实施例提供的一种线程调用上下文编码图的构建方法的示意性流程图;
图13是本申请实施例提供的一种函数的调用上下文的解码方法的示意性流程图;
图14是本申请实施例提供的一种函数的调用上下文的编码装置的示意性框图;
图15是本申请实施例提供的一种函数的调用上下文的解码装置的示意性框图;
图16是本申请实施例提供的另一种函数的调用上下文的编码装置的示意性框图;
图17是本申请实施例提供的另一种函数的调用上下文的解码装置的示意性框图。
具体实施方式
下面将结合附图,对本申请中的技术方案进行描述。
本申请实施例的方案可以应用于编程语言领域。示例性地,本申请实施例的方案能够用于程序分析、调试(debug)或事件日志(events log)等需要区分函数调用上下文的编程语言场景中。
本申请实施例中主要以应用于程序分析中的静态程序分析场景为例对本申请实施例的函数的调用上下文的编码方法进行描述。为了便于理解和描述,下面对静态程序分析以及涉及的相关术语进行说明。
静态程序分析是程序分析中的一种重要分析方法。静态程序分析是在程序编译时,即不运行代码的情况下,通过词法分析、语法分析、控制流分析、数据流分析等技术完成对目标源代码的扫描,以检测出程序隐含的错误问题。图1示出了一种静态程序分析的示意性流程图,如图1所示,静态程序分析的过程通常可以分为两个阶段:抽象阶段和规则匹配阶段。抽象指的是通过静态分析算法对源程序或者说源码(source code)进行变形,构建程序表示以表达程序结构或程序变量等。例如,程序结构可以通过抽象语法树(abstract syntax tree,AST)、函数调用图(call graph,CG)或控制流图(control flow graph,CFG)等方式表示。程序变量可以通过将数组或容器抽象为一个对象的方式表示。规则匹配指的是在上述抽象得到的程序表示的基础上,定义目标分析或检测模式,通过正则匹配、语法解析、控制流分析或数据流分析等技术获取程序中满足既定分析或检测模式的代码信息,得到报告结果,例如,警告(warnings)信息。
其中,并行程序的静态程序分析指的是针对多线程、多进程或者多任务并发等程序的静态程序分析。以并行程序中的多线程程序的静态程序分析为例,多线程静态程序分析包括消除线程内变量的共享变量分析、确定临界区域的互斥锁分析、判断语句间执行序关系的并行发生(may happen in parallel,MHP)分析以及弱内存序分析等。共享变量分析用于分析变量的作用域,获得可以被多个线程访问的变量。互斥锁分析用于识别加锁(lock)和释放锁(unlock)语句,得到程序中每条语句对应的互斥锁集合。MHP分析用于判断多线程程序中任意两条语句是否可能并行执行。弱内存序分析用于检测弱内存一致性模型下的存储指令乱序行为以及加载指令乱序行为。存储指令乱序可以为存储-存储重排(store-store reorder)。加载指令乱序可以为加载-加载重排(load-load reorder)。
静态程序分析可以应用于编译器中。具体地,编译器内部大量应用静态程序分析技术实现对程序的变形、优化以及报错等功能。此外,静态程序分析还广泛应用于现代编辑器,例如,可视化工作室代码(visual studio code,VScode),以及各种程序检查工具中,例如,串行程序分析工具和并行程序分析工具中。串行程序分析工具能够用于检查释放后使用(use-after-free)、空指针引用、五点分析、内存泄漏等200多种程序漏洞(bug)。并行程序分析工具能够用于检查数据竞争、死锁、弱内存模型下的指令重排、乱序错误等。
程序中包含了多种函数调用关系,同一个函数可能存在多个不同的函数调用点,即,同一个函数包括多个不同的调用上下文。上下文敏感(context-sensitive)和上下文不敏感(context-insensitive)针对的是在程序分析或debug等应用中是否区分函数的不同调用点。上下文敏感指的是区分函数的不同调用点,即区分一个函数的不同的调用上下文。上下文不敏感指的是不区分函数的不同调用点,即不区分一个函数的不同的调用上下文。下面结合如下代码说明区分函数不同的调用上下文对指针分析精度的影响。
main(){
*p=&a;
*q=&b;
func(p);
func(q);
}
func(int*input){
XXX=*input;
}
在区分函数的不同调用上下文的情况下,即在上下文敏感的情况下,分析器能够区分函数func在第一次调用(call1,c1)和第二次调用(call2,c2)时的不同的调用位置,得到变量输入(input)在call1时指向变量a,在call2时指向变量b,表示为input→{c1:a,c2:b};在不区分函数的不同调用上下文的情况下,即在上下文不敏感的情况下,分析器不区分函数func在call1和call2时的不同的调用位置,得到变量input同时指向变量a和变量b,表示为input→{a,b}。显然,若分析器能够区分函数func在call1和call2时的不同的调用位置,则能够在很大程度上提升指针分析的精度。
因此,区分一个函数的不同的调用上下文能够大大提高分析精度,是程序分析、debug等编程领域的一项重要任务。
通过函数调用链能够区分函数的不同的调用上下文。以静态程序分析为例,源码中任意一条语句的位置可以通过两种方式表示,即上下文敏感的表示方法和上下文不敏感的表示方法。上下文不敏感表示方法指的是仅记录语句的位置,例如,该语句的行号;上下文敏感的表示方法指的是记录语句的位置和上下文,例如,该语句所在函数的完整的函数调用链。比如,可以通过函数调用串表示目标函数的函数调用链,即从主(main)函数开始到达该语句所在函数的完整函数调用串[call1,call2,…calli],用于表示从main函数开始至目标函数的调用路径 其中,call1,call2,…calli分别表示第i次调用,i为正整数,f 1和f 2分别该函数调用路径上的表示不同的函数,f target表示目标函数,即该语句所在的函数。
图2示出了一种通过函数调用链区分函数不同的调用上下文的效果图。图2中的函数调用链的源码如下所示。
1:locktype 1;
2:int main(){
3:…
4:func();
5:func();
6:…
7:int func(){
8:threadtype tid;
9:fork(tid,thread);
10:…
11:join(tid);
12:…
13:void thread(){
14:lock(l);
15:…
16:unlock(l);
17:…
图2中示出了静态程序分析中的函数调用图,图2中示出的线程均为静态分析得到的静态线程(static thread),包括main函数对应的静态线程STmain和第9行的fork函数对应的静态线程STline9。通过函数的调用路径表达第13行的线程(thread)函数的不同的调用上下文。例如,由第4行(line4)处的函数调用call1,经过第9行(line9)处的复刻(fork)函数调用表达了thread的一个调用上下文,可以表示为thread1:call1(line4)→fork(line9);而由第5行(line5)处的函数调用call2,经过line9处的复刻函数调用表达了另一个thread的一个上下文,比如,可以表示为thread2:call2(line5)→fork(line9)。
通过保存的函数调用链即可区分函数的不同的调用上下文,然而,函数调用链仍然具有很高的空间开销,当函数调用链本身过长时,例如,实际程序中,10万行级别的程序的一条函数调用链的长度通常为10-13个左右,存储该函数调用链需要花费巨大的存储开销。
函数调用上下文编码能够用于表示函数调用链,减少存储开销。图3示出了一种函数调用上下文编码的效果图。例如,图3中的(a)可以称为函数调用图(call graph),该图中的节点A、B、C、D、E、F、G分别表示不同的函数,函数之间的边可以称为函数调用边,用于表示一条具体且唯一的函数调用指令。例如,一条函数调用指令在程序语言中可以表示为A(),即函数A调用其他函数。通过至少一条边相连的两个函数之间存在调用关系,该两个函数可以理解为一个节点对(pair)。图3的(b)为函数调用上下文编码图,即对函数调用图中的函数调用边进行编码得到的图,每条边上的数值为编码(encoding)值。例如,该数值可以为整数。一个节点pair中的两个节点之间的边可能不止一条,该两个节点之间的所有边上的encoding数值不同。不同的节点pair中的边上的encoding数值可以相同。图3中未标注encoding数值的边对应的encoding数值可以为0。这样,任一条函数调用链均可以通过一个编码ID表示,例如,函数调用链ACF的编码ID为2,用于表示函数A调用函数C,再调用函数F,二元组<F,2>即为函数调用链ACF的唯一编码。
然而,函数调用上下文编码中消除了“线程”信息,无法表示多线程中的函数的不同上下文,即无法从编码后的信息中得到线程信息。如图3所示,假设函数B中包含一条线程创建语句fork(D),含义为函数B创建了一个子线程,该子线程的入口函数为函数D。在该情况下,图3中包括两个线程:线程1(thread1)和线程2(thread2),其中,thread1的入口函数为函数A,thread2的入口函数为函数D。函数F具有3条不同的函数调用链,即0:ABDF、1:ACDF和2:ACF,分别对应编码<F,0>、<F,1>和<F,2>。从该编码中无法得到函数F所属的线程的信息,即<F,2>和<F,1>属于thread1,<F,0>属于thread2。
为了获得函数的上下文所属的线程信息,需要对函数调用链对应的编码进行解码(decoding),还原得到原始的函数调用链,进而得到线程信息。例如,对于编码<F,0>,解码为原始的函数调用链ABDF,其中,该函数链中调用了函数B,创建了thread2,D为thread2的入口函数,进而得到ABDF属于thread2。然而,解码过程性能开销较大,若在分析过程中反复通过解码来获得函数的调用上下文所在的线程的信息,则会导致较大的分析时间开销,影响分析效率。
本申请实施例提出一种函数的调用上下文的编码方法,能够区分多线程中的函数的不同的调用上下文,有利于提高分析效率和分析精度。
图4示出了本申请实施例提供的一种应用场景的示意图。示例性地,本申请实施例的方案能够应用于静态程序分析的场景中。例如,如图4所示,本申请实施例的方法能够应用于静态程序分析器(static program analyzer)中。也就是说静态程序分析器可以采用本申请实施例提供的方法700对函数的调用上下文进行编码。示例性地,如图4所示静态程序分析器可以包括变量依赖分析模块、共享变量识别模块、互斥锁分析模块以及MHP分析模块等分析模块。变量依赖分析模块也可以称为定义(define)-使用(use)模块,可以表示为def-use或者use-def,用于分析变量之间的依赖关系。
例如,如图4所示,将程序代码和规则计算公式输入静态程序分析器中。程序代码可以为源码(source code)或中间表示(intermediate representation,IR)。规则计算公式可以通过结构化查询语言(structured query language,SQL)表示,用于实现规则匹配。静态程序分析器可以利用输入的规则计算公式,如图4中的XXX公式,对程序抽象后得到的结果进行计算,得到分析结果,例如,警告(warning)信息。如图4所示,warning中可以包括可能存在问题的语句,比如图4中的statement1(S1)即表示第一条语句。静态程序分析器利用本申请实施例中的方法对源码或IR进行处理,得到函数的调用上下文的编码。该编码作为程序抽象后的结果,可以视为静态程序分析器的分析基础。静态程序分析器可以基于函数的调用上下文的编码和规则计算公式执行相应的分析操作,得到警告信息。
如前所述,静态程序分析包括抽象阶段和规则匹配阶段,图4中的静态程序分析器仅示出了分析模块,该分析模块可以应用于规则匹配阶段。静态程序分析器还可以包括其他模块,用于实现抽象阶段中的操作。
为了更好的描述本申请实施例的方法,下面结合图5对本申请实施例提供的一种静态程序分析器600进行说明。分析器600可以采用本申请实施例中的方法对函数的调用上下文进行编码。
图5示出了本申请实施例提供的一种静态程序分析器的示意性框图。图5中的分析器600包括调用关系构建模块610、调用关系编码构建模块620、函数的调用上下文编码模块630、函数的调用上下文解码模块640和分析模块650。
调用关系构建模块610用于对程序代码进行分析,得到程序代码中的多个线程之间的创建关系。
其中,程序代码可以为源码,也可以为中间代码。
程序代码中的多个线程之间的创建关系可以通过线程关系图(thread graph,TG)表示,也可以通过链表方式表示,还可以通过其他方式表示,本申请实施例对此不做限定。
本申请实施例中仅以TG表示多个线程之间的创建关系为例进行说明。
可选地,调用关系构建模块610可以包括线程关系图构建模块611,线程关系构建模块611用于对程序代码进行分析,得到程序代码中的多个线程之间的创建关系。
具体地,线程关系图构建模块611以线程入口函数为起点,搜索该线程入口函数的所有子函数构成一个线程节点,根据线程之间的创建关系将线程节点连接起来得到线程关系图。
在一种实现方式中,调用关系构建模块610还可以用于对程序代码进行分析,得到程序代码中的多个函数之间的调用关系。
多个函数之间的调用关系可以通过函数调用图(call graph,CG)表示,也可以通过链表方式表示,还可以通过其他方式表示,本申请实施例对此不做限定。
本申请实施例中仅以CG表示多个函数之间的调用关系为例进行说明。
可选地,调用关系构建模块610可以包括函数调用图构建模块612,函数调用图构建模块612用于对程序代码进行分析,得到程序代码中的多个函数之间的调用关系。
进一步地,函数调用图构建模块612可以用于得到线程内的多个函数之间的调用关系。
线程内的多个函数之间的调用关系可以通过线程内的CG表示。在该情况下,函数调用图构建模块612也可以称为线程内函数调用图构建模块612。该模块612的输入可以包括一个线程节点内的所有函数,通过分析该线程内的所有函数之间的调用关系,并为每个函数构建一个函数节点,将这些函数节点基于调用关系连接起来得到线程内的函数调用图。
关于调用关系构建模块610的具体描述可以参见方法700中的步骤S710中的描述。
调用关系编码构建模块620用于对多个线程之间的创建关系进行编码,得到多个线程之间的创建关系对应的编码值。
多个线程之间的创建关系对应的编码值可以通过线程调用上下文编码图(thread calling context encoding graph,TEG)表示,也可以通过链表方式表示,还可以通过其他方式表示,本申请实施例对此不做限定。
本申请实施例中仅以TEG表示多个线程之间的创建关系对应的编码值为例进行说明。
可选地,调用关系编码构建模块620可以包括线程调用上下文编码图构建模块621,线程调用上下文编码图构建模块621接收线程关系图构建模块611输出的线程关系图,将调用上下文编码算法作用于线程关系图中,为线程关系图中的每条边计算编码值,即多个线程之间的创建关系对应的编码值。
在一种实现方式中,调用关系编码构建模块620还可以用于对多个函数之间的调用关系进行编码,得到多个函数之间的调用关系对应的编码值。
多个函数之间的调用关系对应的编码值可以通过函数调用上下文编码图(callcalling context encoding graph,CEG)表示,也可以通过链表方式表示,还可以通过其他方式表示,本申请实施例对此不做限定。
本申请实施例中仅以CEG表示多个函数之间的调用关系对应的编码值为例进行说明。
可选地,调用关系编码构建模块620可以包括函数调用上下文编码图构建模块622。
进一步地,函数调用上下文编码图构建模块622可以用于得到线程内的多个函数之间的调用关系对应的编码值。在该情况下,函数调用上下文编码图构建模块622也可以称为线程内函数调用上下文编码图构建模块622。该模块622接收线程内的函数调用图构建模块612输出的线程内的函数调用图,将调用上下文编码算法作用于线程内的函数调用图中, 为线程内的函数调用图中的每条边计算编码值,即线程内的多个函数之间的调用关系对应的编码值。
关于调用关系编码构建模块620的具体描述可以参见方法700中的步骤S720中的描述。
函数的调用上下文编码模块630用于得到目标函数的调用上下文的编码结果,为分析模块650提供目标函数的调用上下文的编码的功能。
模块630的输入为目标函数的调用上下文信息,输出为目标函数的调用上下文的编码结果,即编码后的压缩数据。
其中,目标函数的调用上下文的编码结果包括目标函数所属的线程的上下文的编码结果。
可选地,目标函数的调用上下文的编码结果还包括目标函数的函数调用上下文的编码结果。
进一步地,目标函数的函数调用上下文的编码结果指的是目标函数在所属线程内的函数调用上下文的编码结果。
具体地,模块630将目标函数的调用上下文信息在TEG和线程内的CEG中进行路径匹配,得到目标函数的调用上下文的编码结果。
关于调用上下文编码模块630的具体描述可以参见方法700中的描述。
函数的调用上下文解码模块640用于得到目标函数的函数调用链。
模块640的输入为目标函数的调用上下文的编码结果,输出为目标函数的函数调用链。
具体地,模块640将目标函数的调用上下文的编码结果在TEG和线程内的CEG中进行路径匹配,得到目标函数的函数调用链。
关于调用上下文解码模块640的具体描述可以参见方法700中的描述。
分析模块650用于执行对程序代码的静态分析。示例性地,分析模块650可以包括图4中所示的任一个或多个分析模块。或者,分析模块650中也可以包括其他分析模块。
图5中所示的函数的调用上下文编码模块630独立于分析模块650,应理解,图5中的连接关系仅为示例,函数的调用上下文编码模块630还可以集成于分析模块650中。
图5中所示的函数的调用上下文解码模块640独立于分析模块650,应理解,图5中的连接关系仅为示例,函数的调用上下文解码模块640还可以集成于分析模块650中。
应理解,图4和图5中仅以本申请实施例中的方法应用于静态程序分析的场景为例进行说明,不对本申请实施例的方法的应用场景构成限定。例如,本申请实施例中的方法还可以作为根技术应用于多线程动态分析工具、debug和静态分析工具中。
图6示出了本申请实施例的一种函数的调用上下文的编码方法700的示意性流程图。方法700包括步骤S710至步骤S750。下面对步骤S710至步骤S750进行详细说明。
S710,对程序代码进行分析,得到程序代码中的多个线程之间的创建关系。
示例性地,步骤S710可以由图5中的调用关系构建模块610执行,即将程序代码作为调用关系构建模块610的输入,经过调用关系构建模块610的处理后输出程序代码中的多个线程之间的创建关系。
程序代码可以为源码,也可以为中间代码。中间代码也可以称为中间表示。示例性地,将源码通过编译器前端处理后得到中间代码。例如,编译器前端可以采用低级虚拟机(low level virtual machine,LLVM)编译器前端Clang,经过Clang处理后得到llvm bc格式的文件,bc为文件后缀。llvm bc格式的文件也可以称为llvm bc中间代码,将lvm bc中间代码作为步骤S710中的程序代码。
程序代码中可以包括多个线程。其中,一个线程包括该线程的线程入口函数以及该线程入口函数的子函数。该线程入口函数以及该线程入口函数的子函数的集合可以作为一个“函数集合体”。在静态程序分析中,该“函数集合体”也可以称为“静态线程的函数集合体”。
线程入口函数可以包括两种,一种为程序代码中的根函数。根函数指的是在该程序代码中没有被其他函数调用的函数。图7示出了一个函数调用图,用于表示程序代码中的多个函数之间的调用关系。图7中的多个节点分别表示多个函数,函数之间的边(连接线)表示函数之间的调用关系。箭头指向的一端表示被调函数(callee),另一端表示调用者函数(caller)。图7所示的程序代码中包括函数threadentry0、函数A、函数threadentry1、函数B、函数C、函数threadentry2、函数D和函数E。如图7所示的函数threadentry0没有被其他函数调用,threadentry0可以作为图7所示的程序代码中的根函数。
另一种为线程创建语句所创建的函数。例如,线程创建语句可以为多线程创建(pthread_create)语句。线程创建语句用于创建线程。调用线程创建语句的函数即为线程创建函数,线程创建语句所述创建的函数为线程入口函数。由该方式得到的线程入口函数也可以称为子线程入口函数。
在本申请实施例中,该线程创建语句所创建的函数也可以称为调用该线程创建语句的函数所创建的函数,即线程创建函数所创建的函数。相应地,该线程创建语句所创建的线程也可以称为调用该线程创建语句的函数所创建的线程,即线程创建函数所创建的线程。
例如,图7中的函数A中调用线程创建语句,即函数A为线程创建函数,该线程创建语句创建了线程thread1,具体地,该线程创建语句所创建的函数为函数threadentry1,函数threadentry1为thread1的线程入口函数。同理,函数B和函数C中调用线程创建语句,即函数B和函数C为线程创建函数,该线程创建语句创建了线程thread2,具体地,该线程创建语句所创建的函数为函数threadentry2,函数threadentry2为thread2的线程入口函数。
这样,图7中包括三个线程:thread0、thread1和thread2,thread0的线程入口函数为threadentry0,可以表示为entryfunc:threadentry0,thread1的线程入口函数为函数threadentry1,可以表示为entryfunc:threadentry1,thread2的线程入口函数为函数threadentry2,可以表示为entryfunc:threadentry2。
线程入口函数的子函数指的是以该线程入口函数作为调用起点,在不跨越线程创建语句的情况下被调用的所有函数。
例如,如图7所示,thread1的线程入口函数为函数threadentry1,函数threadentry1的子函数包括函数threadentry1调用的函数B和函数threadentry1调用的函数C。
程序代码中的多个线程包括父线程和子线程,父线程中的线程创建函数用于创建子线程。即子线程是由父线程创建的线程。也就是说,若一个线程中包括用于创建另一个线程的线程创建函数,则可以理解一个线程创建了另一个线程,两个线程之间存在创建关系。
存在创建关系的两个线程,即一组父线程和子线程,可以称为一个线程对(pair)。 父线程中的函数可以仅创建一次子线程,也可以创建多次子线程。由此,一个线程pair中可以包括一个创建关系,也可以包括多个创建关系。
以图7中的函数调用图为例,图7的主线程为thread0,thread0的入口函数为函数threadentry0,函数threadentry0调用函数A,在该情况下,函数A所在的线程为thread0。函数A为线程thread1的线程创建函数,在函数A被调用时即创建一个子线程thread1。thread0为thread1的父线程,thread1为thread0的子线程。因此,线程thread0创建了一个thread1,即thread0和thread1之间存在1个创建关系。thread1的线程入口函数为函数threadentry1。函数threadentry1调用函数B和函数C,在该情况下,函数B和函数C所在的线程为thread1。函数B和函数C均为线程thread2的线程创建函数,在函数B或函数C被调用时即创建子线程thread2。thread1为thread2的父线程,thread2为thread1的子线程。函数threadentry1对函数B进行了两次调用,函数B在每次被调用时均创建了一个线程thread2,即函数B创建了两个thread2。函数threadentry1对函数C进行了一次调用,函数C在被调用时创建了一个线程thread2,即函数C创建了一次thread2。因此,线程thread1创建了三次thread2,或者说thread2创建了三个thread2,即thread1和thread2之间存在3个创建关系。
父线程和子线程之间的创建关系与父线程中的线程创建函数的函数调用上下文是一一对应的。也就是说,父线程和子线程之间的创建关系的数量和父线程中的线程创建函数的函数调用上下文的数量是相同的。
线程内的函数的函数调用上下文指的是,在该线程内该函数被调用的路径。在该线程内该函数被调用的路径的起点为该线程的线程入口函数。对于同一个函数而言,不同的函数调用路径对应不同的函数调用上下文。如图7所示,thread1为thread2的父线程。由于thread1中的函数B和函数C均创建了thread2的线程入口函数threadentry2,因此,thread1中的线程创建函数包括函数B和函数C。在thread1中,函数B被函数threadentry1调用了两次,或者说是,函数B在两个位置分别被函数threadentry1调用。函数B被函数threadentry1调用了两次,对应不同的函数调用路径,即函数B具备两个不同的函数调用上下文。在thread1中,函数B具备两个函数调用上下文,函数C具备一个函数调用上下文,也就是说,thread1的线程创建函数包括三个函数调用上下文,分别对应thread1和thread2之间的3个创建关系。
可选地,多个线程之间的创建关系可以通过线程关系图(thread graph,TG)表示。
示例性地,TG可以通过图5中的线程关系图构建模块611得到。
TG中包括多个线程节点以及线程节点之间的边(连接线)。其中,TG中的不同线程节点用于表示不同线程,两个线程节点之间的边用于表示两个线程之间的创建关系,或者可以理解为用于区分父线程和子线程。在TG中父线程对应的节点为父线程节点,子线程对应的节点为子线程节点。如前所述,两个线程之间可能存在多个创建关系,相应地,TG中的两个线程节点之间可以包括多条边,分别对应多次线程创建。
例如,图8示出了一种与图7所示的函数调用图相对应的线程关系图。图8中包括3个线程节点,该3个线程节点分别代表图7中的3个线程thread0、thread1和thread2。如图8所示,可以通过该三个线程的线程入口函数表示该3个线程,即threadentry0、threadentry1和threadentry2。如图8所示,threadentry0和threadentry1之间的一条边表示 thread0和thread1之间的一个创建关系,threadentry1和threadentry2之间包括三条边,分别表示thread1和thread2之间的三个创建关系。
应理解,此处仅以图的形式表示多个线程之间的创建关系,还可以通过其他数据结构表示多个线程之间的创建关系,例如,通过链表的形式表示多个线程之间的创建关系,本申请实施例对此不做限定。
进一步地,步骤S710还包括:对程序代码进行分析,得到程序代码中的多个函数之间的调用关系。
示例性地,步骤S710可以由图5中的调用关系构建模块610执行,即将程序代码作为调用关系构建模块610的输入,经过调用关系构建模块610的处理后还可以输出程序代码中的多个函数之间的调用关系。
存在调用关系的两个函数可以称为一个函数pair。由于一个函数可以对另一函数进行多次调用,因此,一个函数pair中可以包括一个调用关系,也可以包括多个调用关系。也就是说,在一个函数pair中,其中一个函数可以仅调用一次另一个函数,也可以多次调用另一个函数。例如,如图7所示,函数threadentry1对函数B进行了两次调用。即函数threadentry1和函数B之间存在两个调用关系,该两次调用分别对应不同的函数调用上下文。
可选地,多个函数之间的调用关系可以通过函数调用图(call graph,CG)表示。例如,如图7所示的函数调用图。
示例性地,CG可以通过图5中的函数调用图构建模块612得到。
CG中包括多个函数节点以及函数节点之间的边(连接线)。其中,CG中的函数节点用于表示函数,两个函数节点之间的边用于表示两个函数之间的调用关系,即用于区分调用者函数(caller)和被调函数(callee)。或者可以理解为,两个函数节点之间的边可以指示两个函数之间的函数调用语句。如前所述,两个函数之间可能存在多次调用,相应地,CG中的两个函数节点之间可以包括多条边,分别对应多次函数调用。
应理解,本申请实施例中仅以图的形式表示多个函数之间的调用关系,还可以通过其他数据结构表示多个函数之间的调用关系,例如,通过链表的形式表示多个函数之间的调用关系,本申请实施例对此不做限定。
具体地,该多个函数之间的调用关系可以为该程序代码中的全部函数之间的调用关系,例如,如图7所示的程序代码中的多个函数之间的调用关系。
或者,该多个函数之间的调用关系可以包括多个线程内的多个函数之间的调用关系。也就是说,分别基于不同的线程表示该程序代码中的全部函数之间的调用关系。
在一个线程内,多个函数之间的调用关系的起点为该线程的线程入口函数。在一个线程内的多个函数之间不存在线程创建关系。也就是说,一个线程内的多个函数之间的调用关系包括以该线程的线程入口函数为起点、且不跨越线程创建语句的多个函数之间的调用关系。
示例性地,可以通过多个线程内的CG表示该多个线程内的多个函数之间的调用关系。每个线程内的CG中仅包括属于该线程的线程入口函数节点以及该线程入口函数的子函数节点以及该线程内的函数节点之间的边。图9示出了与图7所示的函数调用图对应的线程内的函数调用图。图9包括3个线程内的CG,即thread0内的CG、thread1内的CG和thread2 内的CG。thread0内的函数之间的调用关系的起点为threadentry0。thread0内的多个函数之间的调用关系包括:threadentry0调用函数A。thread1内的函数之间的调用关系的起点为threadentry1,thread1内的多个函数之间的调用关系包括threadentry1两次调用函数B,threadentry1调用函数C。thread2内的函数之间的调用关系的起点为threadentry2。thread2内的多个函数之间的调用关系包括:threadentry2调用函数D,threadentry2调用函数E。
在静态程序分析中,通常对程序代码中的所有指令进行分析,这样可以得到程序代码中的全部线程之间的创建关系。
示例性地,步骤S710包括步骤S711至步骤S712。
S711,对程序代码中的指令进行分析,得到程序代码中的函数调用语句和线程创建语句。
具体地,扫描程序代码,得到线程创建语句和函数调用语句。例如,线程创建语句可以为pthread_create语句。线程创建语句的位置即为线程创建的位置。得到程序代码中的线程创建语句可以理解为得到程序代码中的线程的创建位置。函数调用语句的位置即为函数调用的位置,得到程序代码中的函数调用语句可以理解为得到函数调用的位置。
在本申请实施例中,一条“语句”也可以理解为一条“指令”。例如,函数调用语句即为函数调用指令。
S712,根据函数调用语句和线程创建语句得到多个线程之间的创建关系和多个线程内的多个函数之间的调用关系。
以线程入口函数作为起点,该线程入口函数以及该线程入口函数的子函数构成一个线程,在TG中表示为一个线程节点。根据线程内的函数之间的函数调用语句和线程创建语句得到线程之间的创建关系,两个线程之间的创建关系在TG中表示为两个线程节点之间的边。
具体地,由线程入口函数开始遍历函数调用语句,在不跨越线程创建语句和用于调用线程入口函数的函数调用语句的情况下,得到的所有被调用的函数即为该线程入口函数的子函数。也就是说该线程入口函数的子函数均是通过普通函数调用语句调用的函数。普通函数调用语句指的是除了线程创建语句的函数调用语句。为了便于描述,本申请实施例中的普通函数调用语句均称为函数调用语句。该线程入口函数以及该线程入口函数的子函数的集合可以作为一个“函数集合体”。一个“函数集合体”可以以一个线程节点的形式被创建在TG中,也就是说,TG中的一个线程节点也可以理解为一个“函数集合体”。例如,图8中的thread0对应的函数集合体包括:函数threadentry0和函数threadentry0调用的函数,即函数A;thread1对应的函数集合体包括:函数threadentry1以及函数threadentry1调用的所有函数,即函数B和函数C;thread2对应的函数集合体包括:函数threadentry2以及函数threadentry2调用的所有函数,即函数D和函数E。
根据一个线程内的所有函数之间的函数调用语句得到一个线程内的多个函数之间的调用关系,即根据一个函数集合体中的多个函数之间的函数调用语句得到一个线程内的多个函数之间的调用关系。一个函数集合体中的函数可以以节点的形式被创建在一个图中,例如,如图9所示的线程内的CG。线程内的CG中两个节点之间的边用于表示函数之间的调用关系,例如,两个节点之间的边为该两个函数之间的函数调用语句。例如,图9中threadentry0和A之间的有向连接线表示函数threadentry0调用函数A的语句。
根据线程创建语句可以区分父线程和子线程,在TG中分别表示为父线程节点和子线程节点,将父线程节点和子线程节点相互连接即构成TG。父线程节点和子线程节点之间的边的数量可以根据父线程中的用于创建子线程的线程创建函数的调用上下文确定。其中,线程内的一个函数的调用上下文可以根据前述线程内的多个函数之间的调用关系确定。也就是说,父线程中的线程创建函数的调用上下文可以根据父线程内的多个函数之间的调用关系确定。
需要说明的是,在构建线程内的CG的过程中,可以对图进行其他的处理,以得到线程内的CG。例如,进行相关强连通的图分析。本申请对此不做限定。
如前所述,TG可以用于表示程序代码中的多个线程之间的创建关系,线程的CG可以用于表示线程内的多个函数之间的调用关系。构建TG也可以理解为得到多个线程之间的创建关系。构建线程内的CG也可以理解为得到多个线程内的多个函数之间的调用关系。
下面举例说明TG和线程内的CG的构建方法。
在一种实现方式中,步骤S710中可以包括步骤S713和步骤S714。
S713,根据CG确定线程内的CG。
如前所述,CG能够用于表示程序代码中的多个函数之间的调用关系。或者说,CG是通过对程序代码进行分析得到的。根据程序代码中的多个函数之间的调用关系即可得到线程内的多个函数之间的调用关系,因而,根据CG能够得到线程内的CG。
示例性地,根据CG中的线程入口函数和该线程入口函数的子函数之间的调用关系得到该线程入口函数对应的线程中的多个函数之间的调用关系,即得到线程内的CG。
例如,根据如图7所示的CG得到如图9所示的三个线程内的CG。
S714,根据CG和线程内的CG得到TG。
将CG中的一个线程入口函数和该线程入口函数的子函数作为TG中的一个线程节点。TG中线程节点的数量等于CG中线程入口函数节点的数量。在TG的线程节点中可以通过线程入口函数表示该线程入口函数对应的线程。若在CG中,一个线程入口函数节点与其他函数节点之间存在线程创建边,则在TG中,为该线程入口函数对应的线程节点与其他函数所属的线程节点之间构建边。线程创建边用于表示线程创建语句。父线程节点与子线程节点之间的边的数量等于父线程节点中的用于创建子线程的线程创建函数的调用上下文的数量。根据线程内的CG可以确定线程内的每个函数的调用上下文。
例如,根据如图9所示的thread1所对应的线程内的CG可以得到函数B具有两个不同的调用上下文,函数C具有一个调用上下文。相应地,在TG中,threadentry1和threadentry2之间具有3条不同的边,以表示三条不同的调用路径。
应理解,上述得到程序代码中的多个线程之间的创建关系和多个线程内的多个函数之间的调用关系的两种实现方式仅为示意,还可以通过其他方法得到多个线程之间的创建关系和多个线程内的多个函数之间的调用关系。本申请实施例对得到多个线程之间的创建关系和多个线程内的多个函数之间的调用关系的具体实现方式不做限定。
S720,对多个线程之间的创建关系进行编码(encode),得到多个线程之间的创建关系对应的编码值。
示例性地,步骤S720可以由图5中的调用关系编码构建模块620执行。即将多个线程之间的创建关系作为调用关系编码构建模块620的输入,经过调用关系编码构建模块 620的处理后输出程序代码中的多个线程之间的创建关系对应的编码值。
该编码值可以通过数字表示,例如,编码值可以为整数。
在两个线程之间存在多个创建关系的情况下,该多个创建关系对应的编码值不同。例如,在TG中的两个线程节点之间包括多条边的情况下,该多条边对应的编码值不同。
可选地,程序代码中的多个线程之间的创建关系对应的编码值是利用调用上下文编码(calling context encoding)算法对程序代码中的多个线程之间的创建关系进行编码得到的。
线程的上下文的编码值等于该线程的上下文中的多个线程之间的创建关系的编码值之和,该算法能够保证线程的不同的上下文的编码值不同。
也就是说,通过调用上下文编码算法对多个线程之间的创建关系进行编码,能够保证线程的不同上下文的编码结果不同,使得线程的上下文的编码结果唯一指示线程的上下文。应理解,本申请实施例中还可以采用其他方式对多个线程之间的创建关系进行编码,只要满足线程的不同上下文的编码值不同即可。
进一步地,步骤S720还包括:对程序代码中的多个函数之间的调用关系进行编码,得到多个函数之间的调用关系对应的编码值。
具体地,程序代码中的多个函数之间的调用关系对应的编码值与程序代码中的多个函数之间的函数调用语句对应。
可替换地,步骤S720还包括:对多个线程内的多个函数之间的调用关系进行编码,得到多个线程内的多个函数之间的调用关系对应的编码值。
具体地,多个线程中的一个线程内的多个函数之间的调用关系对应的编码值与一个线程内的多个函数之间的函数调用语句对应。
该编码值可以通过数字表示,例如,编码值可以为整数。
在两个函数之间存在多个调用关系的情况下,该两个函数之间的多个调用关系对应的编码值不同,或者说,多次调用时该两个函数之间的函数调用语句对应的编码值不同。
可选地,多个线程内的多个函数之间的调用关系对应的编码值是分别利用调用上下文编码算法对多个线程内的多个函数之间的调用关系进行编码得到的。
线程内的函数的函数调用上下文的编码值等于线程内的该函数的函数调用上下文中的多个函数之间的调用关系的编码值之和。该算法能够保证线程内的函数的不同的函数调用上下文的编码值不同。
通过调用上下文编码算法对多个线程内的多个函数之间的调用关系进行编码,能够保证线程内的函数的不同的函数调用上下文的编码结果不同,使得线程内的函数的不同的函数调用上下文编码结果唯一指示线程内的函数的函数调用上下文。
应理解,本申请实施例中还可以采用其他方式对线程内的多个函数之间的调用关系进行编码,只要满足线程内的函数的不同的函数调用上下文的编码值不同即可。
下面以TG和线程内的CG为例对步骤S720进行说明。
示例性地,利用调用上下文编码算法对线程内的CG中的边进行编码,得到线程内的CG中的边上的编码值。例如,如图10所示,该编码数值可以通过线程内的函数调用上下文编码图(callcalling context encoding graph,CEG)表示。线程内的CEG中包括线程内的CG中的函数节点以及函数节点之间的边,还包括边上的编码值。例如,该步骤可以由图5中的线程内的函数调用上下文编码图构建模块622执行。
具体地,在线程内的CG中,函数节点之间的边可以称为函数调用边,通过函数调用边相连的两个函数节点可以理解为一个函数节点对。对每个函数调用边进行编码,得到每个函数调用边上的编码值。在一个函数节点对中的两个函数节点之间的边的数量大于或等于2的情况下,该两个函数节点之间的所有边上的编码数值不同。不同的函数节点对中的边上的编码数值可以相同,也可以不同。图10所示的线程内的CEG中包括多个函数节点以及多个函数节点之间的边,例如,函数节点threadentry1和函数节点B之间包括两条边,即表示函数threadentry1调用了两次函数B,该两条边上的编码值分别为0和1,分别表示函数threadentry1和函数B之间的两个调用关系对应的编码值分别0和1。
示例性地,利用调用上下文编码算法对TG进行编码,得到TG中的边上的编码值。例如,如图11所示,该编码值可以通过线程调用上下文编码图(thread calling context encoding graph,TEG)表示。TEG中包括TG中的线程节点以及线程节点之间的边,还包括边上的编码值。例如,该步骤可以由图5中的线程调用上下文编码图构建模块621执行。
具体地,在TG中,线程节点之间的边可以称为线程调用边,通过线程调用边相连的两个线程节点可以理解为一个线程节点对。对每个线程调用边进行编码,得到每个边上的编码值。在一个线程节点对中的两个线程节点之间的边的数量大于或等于2的情况下,该两个线程节点之间的所有边上的编码值不同。不同的线程节点对中的边上的编码值可以相同,也可以不同。例如,图11所示的TEG中包括三个线程节点和三个线程节点之间的多条边。其中,图11中的threadentry1节点和threadentry2节点之间包括三条边,三条边上的编码值分别为0、1和2,分别表示该两个线程之间的三个创建关系对应的编码值为0、1和2。
进一步地,父线程和子线程之间的创建关系对应的编码值与父线程中的线程创建函数的函数调用上下文对应。也就是说,在TEG中的两个线程节点之间包括多个线程调用边的情况下,该多个线程调用边上的编码值与父线程中的线程创建函数的函数调用上下文对应。如图11所示的TEG中,threadentry1节点和threadentry2节点之间包括三条边,三条边上的编码值分别与thread1内的函数B的两个函数调用上下文以及thread1内的函数C的一个函数调用上下文对应。
具体地,可以函数在所属线程内的函数调用上下文进行编码,得到函数在所属线程内的函数调用上下文的编码结果。也就是说,函数在所属线程内的函数调用上下文的编码结果可以用于表示函数在所属线程内的函数调用上下文。在该情况下,父线程和子线程之间的创建关系对应的编码值与父线程中的线程创建函数的函数调用上下文的编码结果是一一对应的。
这样能够保证对编码结果进行解码后能够得到完整的函数调用链,不会丢失函数在其他线程中的调用上下文,具体描述参见方法1700中的描述。
例如,如图12所示,函数B在thread1内的两个函数调用上下文的编码结果分别表示为[B,0]和[B,1],函数C在thread1内的函数调用上下文的编码结果表示为[C,0],在该情况下,[B,0]、[B,1]和[C,0]分别与threadentry1节点和threadentry2节点之间包括三条边上的编码值0、1和2对应。
或者,也可以用其他方式表示线程内的函数的调用上下文,只要线程之间的创建关系对应的编码值与父线程中的线程创建函数的调用上下文一一对应即可。
需要说明的是,步骤S710和步骤S720为可选步骤。
或者,步骤S710和步骤S720的执行主体与步骤S730至步骤S750的执行主体可以相同,也可以不同。示例性地,步骤S720得到的编码值可以是预先编码得到,在执行步骤S730至步骤S750时加载或者调用即可。
S730,获取目标函数的调用上下文信息。
示例性地,步骤S730可以由图5中的函数的调用上下文编码模块630执行。
目标函数的调用上下文信息用于指示目标函数的调用上下文。或者说,目标函数的调用上下文信息用于指示目标函数的调用路径。
示例性地,获取目标函数的调用上下文信息可以为从其他模块或其它设备接收的目标函数的调用上下文信息。或者,获取目标函数的调用上下文信息也可以是从本地加载目标函数的调用上下文信息。本申请实施例对此不做限定。
可选地,目标函数的调用上下文信息包括:目标函数的函数调用链。例如,目标函数的函数调用链为threadentry0→A→threadentry1→C→threadentry2→D,用于表示目标函数D的调用上下文,即函数D是基于上述调用路径被调用的。
示例性地,本申请实施例中的编码方法700可以应用于静态程序分析器中,在分析器包括多个分析模块,每个模块采用的区分函数的调用上下文的方式可能不同。若其中一个模块采用函数调用链的方式区分函数的调用上下文,以函数调用链的形式为其他分析模块提供分析结果。本申请实施例的方法可以获取该分析模块提供的函数调用链,将以函数调用链的形式提供的分析结果转换为编码结果形式表示的分析结果,大大减少内存开销。应理解,此处的应用场景仅为示例,方法700还可以应用于其他场景中。
可选地,目标函数的调用上下文信息包括:目标函数的调用者函数(caller)的调用上下文的编码结果和第一指令。目标函数为调用者函数通过第一指令调用的函数。
也就是说,目标函数作为该调用者函数的被调函数(callee)。根据调用者函数和第一指令即可确定目标函数。
目标函数的调用者函数的调用上下文的编码结果用于指示目标函数的调用者函数的调用上下文。具体地,目标函数的调用者函数的调用上下文的编码结果可以是基于方法700得到的。例如,目标函数的调用者函数的编码结果包括调用者函数所属的线程的上下文的编码结果和调用者函数在所属线程内的函数调用上下文的编码结果。具体描述可以参见后文中的步骤S750和步骤S770。
示例性地,本申请实施例中的编码方法700可以应用于静态程序分析器中,在分析器分析一条指令时,可以对该指令所在的函数(调用者函数的一例)的调用上下文进行编码,得到编码结果,并保存该函数的调用上下文的编码结果。当该函数中包括函数调用语句时,分析器可以根据保存的该函数的调用上下文的编码结果和该函数调用语句对被调函数(目标函数的一例)得到被调函数的编码结果,并保存编码结果。应理解,此处的应用场景仅为示例,方法700还可以应用于其他场景中。
可选地,目标函数的调用上下文信息包括:目标函数调用的被调函数的调用上下文的编码结果和第二指令。该被调函数为目标函数通过第二指令调用的函数。
也就是说将目标函数作为调用者函数,根据被调函数和第二指令即可确定目标函数。
被调函数的调用上下文的编码结果用于指示被调函数的调用上下文。具体地,被调函 数的调用上下文可以是基于方法700得到的。例如,被调函数的调用上下文包括被调函数所属的线程的上下文的编码结果和被调函数在所属线程内的函数调用上下文的编码结果。具体描述可以参见后文中的步骤S750和步骤S770。
示例性地,本申请实施例中的编码方法700可以应用于静态程序分析器中,在分析器分析一条指令时,可以对该指令所在的函数(被调函数的一例)的调用上下文进行编码,得到编码结果,并保存该函数的调用上下文的编码结果。分析器对该函数分析结束时,可以根据保存的该函数的调用上下文的编码结果和调用该函数的函数调用语句得到调用者函数(目标函数的一例)得到被调函数的编码结果,并保存编码结果。应理解,此处的应用场景仅为示例,方法700还可以应用于其他场景中。
可选地,目标函数的调用上下文信息包括:目标函数调用的被调函数的调用上下文的编码结果。该被调函数为目标函数调用的函数。
也就是说将目标函数作为调用者函数,根据被调函数的调用上下文的编码结果即可确定目标函数。
被调函数的调用上下文的编码结果用于指示被调函数的调用上下文。具体地,被调函数的调用上下文可以是基于方法700得到的。例如,被调函数的调用上下文包括被调函数所属的线程的上下文的编码结果和被调函数在所属线程内的函数调用上下文的编码结果。具体描述可以参见后文中的步骤S750和步骤S770。
示例性地,本申请实施例中的编码方法700可以应用于静态程序分析器中,在分析器分析一条指令时,可以对该指令所在的函数(被调函数的一例)的调用上下文进行编码,得到编码结果,并保存该函数的调用上下文的编码结果。分析器对该函数分析结束时,可以根据保存的该函数的调用上下文的编码结果得到调用者函数(目标函数的一例)得到被调函数的编码结果,并保存编码结果。应理解,此处的应用场景仅为示例,方法700还可以应用于其他场景中。
S740,获取程序代码中的多个线程之间的创建关系对应的编码值。其中,程序代码包括该目标函数。
示例性地,步骤S740可以由图5中的函数的调用上下文编码模块630执行。
示例性地,程序代码中的多个线程之间的创建关系对应的编码值可以是通过步骤S720得到。
可替换地,程序代码中的多个线程之间的创建关系对应的编码值可以是从其他模块或设备接收的。
S750,根据目标函数的调用上下文信息和多个线程之间的创建关系对应的编码值对目标函数所属的线程的上下文进行编码,得到目标函数所属的线程的上下文的编码结果。
示例性地,步骤S750可以由图5中的函数的调用上下文编码模块630执行。
其中,目标函数所属的线程的上下文可以理解为目标函数所属的线程与其他线程之间的创建关系。
目标函数所属的线程指的是目标函数的调用上下文所属的线程。也就是说,对于一个函数而言,不同的调用路径可能属于相同的线程,也可能属于不同的线程。为了便于描述,本申请实施例中将目标函数的调用上下文所属的线程简称为目标函数所属的线程。
可选地,目标函数所属的线程的上下文的编码结果用于指示目标函数所属的线程中的 线程入口函数和目标函数所属的线程的上下文的编码值。线程的不同上下文的编码值不同。
这样,通过线程入口函数即可区分目标函数的调用上下文所属的线程,有利于快速区分不同线程中的函数的调用上下文,通过线程的上下文的编码值即可唯一指示该线程的上下文,进一步准确区分线程的不同的上下文,有利于提高分析结果的准确性。
示例性地,目标函数所属的线程的上下文的编码结果可以包括第一元素和第二元素,其中,第一元素用于指示目标函数所属的线程中的线程入口函数,第二元素用于指示目标函数所属的线程的上下文的编码值。
可替换地,目标函数所属的线程的上下文的编码结果可以包括第五元素,第五元素可以用于指示目标函数所属的线程中的线程入口函数和目标函数所属的线程的上下文的编码值。也就是说,第五元素和目标函数所属的线程中的线程入口函数以及目标函数所属的线程的上下文的编码值之间存在对应关系,能够唯一指示一条线程的上下文。
在后文中以三种方式(方式1、方式2和方式3)作为示例对步骤S750的具体实现方式进行说明。
根据本申请实施例中的方案,通过对函数所属的线程的上下文进行编码,编码结果能够指示函数所属的线程的上下文,进而能够区分多线程中的函数的不同调用上下文,有利于提高分析精度。此外,本申请实施例的方案无需对编码结果进行解码即可得到函数所属的线程的信息,能够快速区分函数所属的线程的上下文,节省了解码带来的时间开销,有利于提高分析效率。此外,通过对函数所属的线程的上下文进行编码,空间开销较小,能够有效减少存储线程的上下文信息所导致的存储空间的压力。也就是说,本申请实施例的方案能够在不大量占用存储空间的情况下,区分函数所属的线程的上下文,提高分析精度和分析效率。
可选地,方法700还包括提供第一API,该第一API的输入包括目标函数的调用上下文信息。该API的输出包括目标函数所属的线程的上下文的编码结果。
或者也可以理解为,步骤S730中目标函数的调用上下文信息是通过第一API获取的。该第一API输出步骤S750得到的目标函数所属的线程的上下文的编码结果。
示例性地,该第一API可以输出第一元素和第二元素。或者,该第一API可以输出第五元素。
可选地,方法700还包括步骤S760和步骤S770。
S760,获取程序代码中的多个线程内的多个函数之间的调用关系对应的编码值。
示例性地,步骤S760可以由图5中的函数的调用上下文编码模块630执行。
示例性地,程序代码中的多个线程内的多个函数之间的调用关系对应的编码值可以是通过步骤S720得到的。
可替换地,程序代码中的多个线程内的多个函数之间的调用关系对应的编码值可以是从其他模块或设备接收的。
多个线程中的一个线程内的多个函数之间的调用关系对应的编码值与多个函数之间的函数调用语句对应。
S770,根据目标函数的调用上下文信息和程序代码中的多个线程内的多个函数之间的调用关系对应的编码值对目标函数在所属线程内的函数调用上下文进行编码,得到目标函数在所属线程内的函数调用上下文的编码结果。
示例性地,步骤S770可以由图5中的函数的调用上下文编码模块630执行。
目标函数在所述线程内的函数调用上下文的调用起点为该线程的线程入口函数。目标函数在所属线程内的函数调用上下文指的是目标函数所属线程的线程入口函数至目标函数之间的调用路径。
可选地,目标函数在所属线程内的函数调用上下文的编码结果用于指示目标函数和目标函数在所属线程内的函数调用上下文的编码值。目标函数在所述线程内的不同的函数调用上下文的编码值不同。
示例性地,目标函数在所属线程内的函数调用上下文的编码结果可以包括第三元素和第四元素,其中,第三元素用于指示目标函数,第四元素用于指示目标函数在所属线程内的函数调用上下文的编码值。
在后文中以三种方式(方式1、方式2和方式3)作为示例对步骤S770的具体实现方式进行说明。
根据本申请实施例中的方案,通过对函数在所属线程内的函数调用上下文进行编码,无需对编码结果进行解码即可得到函数在所属线程内的函数调用上下文的信息,有利于快速区分多线程中的函数的调用上下文,进一步提高了分析效率和分析精度。
此外,通过函数在所属线程内的函数调用上下文进行编码,空间开销较小,能够有效减少存储函数的调用上下文信息所导致的存储空间的压力。也就是说,本申请实施例的方案能够在不大量占用存储空间的情况下,区分多线程中的函数的调用上下文,提高分析精度和分析效率。
而且,在本申请实施例中的方案中,根据对函数在所属线程内的函数调用上下文进行编码以及对函数所属的线程的上下文进行编码得到的编码结果,能够快速解码得到函数调用链,有利于其他模块对该编码结果的复用。
可选地,方法700还包括提供第二API,第二API的输入包括目标函数的调用上下文信息。该第二API的输出可以包括目标函数在所属线程内的函数调用上下文的编码结果。
或者也可以理解为,步骤S730中目标函数的调用上下文信息是通过第二API获取的。该第二API输出步骤S770得到的目标函数所属的线程的上下文的编码结果。
需要说明的是,第一API和第二API可以为同一个API,也可以为不同的API。
本申请实施例中仅以第一API和第二API为同一个API为例进行说明,不对本申请实施例构成限定。
在该情况下,该API的输入包括目标函数的调用上下文信息。该API的输出包括目标函数所属的线程的上下文的编码结果以及目标函数所属的线程的上下文的编码结果。
可选地,API输出的形式为四元组的形式,API返回值包括四元组中的第一元素、第二元素、第三元素和第四元素,分别用于指示目标函数所属的线程中的线程入口函数、目标函数所属的线程的上下文编码值、目标函数以及目标函数在所属线程内的函数调用上下文的编码值。
可替换地,API输出的形式为三元组的形式,API返回值包括三元组中的第五元素、第六元素和第七元素,第五元素用于指示目标函数所属的线程中的线程入口函数和目标函数所属的线程的上下文编码值,第六元素用于指示目标函数,第七元素用于指示目标函数在所属线程内的函数调用上下文的编码值。
方式1
在一种实现方式中,目标函数的调用上下文信息包括:目标函数的函数调用链。
若该函数调用链中包括线程创建函数所创建的线程入口函数,则目标函数所属的线程为该函数调用链中最后一个线程创建函数所创建的线程入口函数对应的线程。目标函数在所属线程内的函数调用上下文即为以该最后一个线程创建函数所创建的线程入口函数为调用起点的函数调用上下文。若该函数调用链中不包括线程创建函数所创建的线程入口函数,则目标函数所属的线程为该程序代码的根函数,即该函数调用链中的起点处的函数,所对应的线程,即主线程。目标函数在所属线程内的函数调用上下文即为以根函数为调用起点的函数调用上下文。如图7中的一条函数调用链CS为threadentry0→A→threadentry1→C→threadentry2→D,该函数调用链中最后一个线程创建函数为函数C,则目标函数D所属的线程为函数C所创建的线程入口函数threadentry2所对应的线程thread2。目标函数D在线程thread2内的函数调用上下文以threadentry2为调用起点。再如图7中的一条函数调用链CS为threadentry0→A,该函数调用链中不包括线程创建函数。该函数调用链的起点处的函数为函数threadentry0,则目标函数A所属的线程为函数threadentry0所对应的线程thread0。目标函数A在所属线程thread0内的函数调用上下文以threadentry0为起点。
在函数调用链不包括线程创建函数所创建的线程入口函数的情况下,对目标函数所属的线程进行编码,得到目标函数所属的线程的上下文的编码结果。函数调用链不包括线程创建函数也就是说该函数调用链属于主线程,对主线程进行编码,得到主线程的上下文的编码结果。例如,主线程的上下文的编码值可以设置为0,则该主线程的上下文的编码结果包括主线程的线程入口函数和该编码值。
在函数调用链包括线程创建函数所创建的线程入口函数的情况下,根据该函数调用链中的线程创建函数可以确定该函数调用链中的多个线程之间的创建关系;根据程序代码中的多个线程之间的创建关系对应的编码值确定该函数调用链中的多个线程之间的创建关系对应的编码值;根据该函数调用链中的多个线程之间的创建关系对应的编码值确定目标函数所属的线程的上下文的编码值;根据目标函数所属的线程的上下文的编码值和目标函数所属的线程的线程入口函数可以确定目标函数所属的线程的上下文的编码结果。
确定目标函数所属的线程的上下文的编码值的方式可以根据需要设置,满足线程的不同上下文的编码值不同即可。
示例性地,将函数调用链中的多个线程之间的创建关系对应的编码值求和后的结果作为目标函数所属的线程的上下文的编码值。例如,如图7中的一条函数调用链CS为threadentry0→A→threadentry1→C→threadentry2→D,该CS中的多个线程之间的创建关系对应的编码值包括:threadentry0对应的线程thread0和threadentry1对应的线程thread1之间的创建关系对应的编码值0,以及threadentry1对应的线程thread1和threadentry2对应的线程thread2之间的其中一个创建关系对应的编码值2,两个编码值相加后的结果为2,将2作为函数D所属的线程的上下文的编码值。
示例性地,目标函数所属的线程的上下文的编码结果可以表示为<第一元素,第二元素>的形式。其中的第一元素为目标函数所属的线程的线程入口函数,第二元素为目标函数所属的线程的上下文的编码值。或者,目标函数所属的线程的上下文的编码结果可以表示为<第五元素>的形式,其中第五元素表示对线程入口函数和线程编码值的一种包装,即 <第五元素>和<第一元素,第二元素>之间具有对应关系,第五元素能够用于指示目标函数所属的线程的上下文的编码值和目标函数所属的线程的线程入口函数。例如,第五元素可以为字符串或数字等形式。
可选地,步骤S750包括:在该函数调用链不包括线程创建函数所创建的线程入口函数的情况下执行步骤S11。在该函数调用链包括线程创建函数所创建的线程入口函数的情况下执行步骤S12至步骤S17。
S11:将该函数调用链中的起点处的函数作为目标函数的线程入口函数,确定目标函数所属的线程的上下文的编码结果。
主线程不是其他线程创建的线程,主线程的上下文的编码值可以设置为任意值,例如,主线程的上下文的编码值设置为0。主线程的线程入口函数即为根函数。
如图7中的一条函数调用链CS为threadentry0→A,该CS中不包括由线程创建函数所创建的线程入口函数,将起点处的函数threadentry0作为目标函数A的线程入口函数。确定函数A所属的线程的上下文的编码值为0,函数A所属的线程的上下文的编码结果为<threadentry0,0>。
S12:以函数调用链中的线程创建函数为分割点,将函数调用链分为至少两个子链,该至少两个子链中的每个子链中的起始点为不同的线程入口函数。
这样,每个子链分别属于不同的线程,或者说,每个子链分别对应不同的线程。
例如,如图7中的一条函数调用链CS为threadentry0→A→threadentry1→C→threadentry2→D。该函数调用链中包括两个线程创建函数:函数A和函数C。以函数A和函数C为分割点,将函数调用链分为三个子链CS1、CS2和CS3。其中,CS1为threadentry0→A,CS2为threadentry1→C,CS3为threadentry2→D。
S13:根据多个线程内的多个函数之间的调用关系对应的编码值分别确定至少两个子链中的多个函数之间的调用关系对应的编码值。
示例性地,将该至少两个子链分别作用于该至少两个子链对应的至少两个线程内的CEG中,得到至少两个子链中的多个函数之间的调用关系对应的编码值。
例如,如图7中的一条函数调用链CS为threadentry0→A→threadentry1→C→threadentry2→D的三个子链包括:CS1为threadentry0→A,CS2为threadentry1→C,CS3为threadentry2→D。分别基于图10中的三个线程内的CEG得到该三个子链中的多个函数之间的调用关系对应的编码值。threadentry0调用函数A在thread0内的CEG中对应的编码值为0。threadentry1调用函数C在thread1内的CEG中对应的编码值为0。threadentry2调用函数D在thread2内的CEG中对应的编码值为0。
S14:根据至少两个子链中的多个函数之间的调用关系对应的编码值分别确定至少两个子链中的线程创建函数的函数调用上下文对应的编码结果。
该至少两个子链分别对应至少两个线程,该至少两个线程中至少包括一个父线程和一个子线程。应理解,父线程和子线程为相对的概念。同一个线程为一个线程的父线程的同时,也可以为另一个线程的子线程。例如,线程1创建线程2,线程2创建线程3。线程2为线程3的父线程,线程2为线程1的子线程。
若该至少两个子链中包括n个子链,n为整数,相应地,该至少两个子链中包括n-1个父线程。线程创建函数位于父线程中,即该n-1个父线程包括n-1个第一线程函数。
具体地,根据至少两个子链中第一子链中的多个函数之间的调用关系对应的编码值确定至少两个子链中的线程创建函数的函数调用上下文对应的编码结果。第一子链为至少两个子链中第二子链之外的其他子链,即第一子链包括所有父线程对应的子链。第二子链为函数调用链中位于最尾端的子链。第一子链可以包括一个子链,也可以包括多个子链。
由于步骤S1中以线程创建函数为分割点对函数调用链进行分割,得到至少两个子链,因此,第一子链中的最后一个函数为线程创建函数。
示例性地,将第一子链中的每个子链中的多个函数之间的调用关系对应的编码值之和作为该子链中的线程创建函数的调用上下文对应的编码值。也就是将第一子链作用于第一子链对应的线程内的CEG中,按照函数调用顺序叠加该线程内的CEG中的对应的边上的编码值,得到该子链中的线程创建函数的函数调用上下文对应的编码值。
例如,CS1为threadentry0→A,CS2为threadentry1→C,CS3为threadentry2→D。第一子链包括CS1和CS2。第二子链为CS3。将CS1作用于图10所示的thread0对应的线程内的CEG上,按照threadentry0调用函数A的顺序得到函数A的函数调用上下文对应的编码值为0,线程thread0内的函数A的函数调用上下文的编码结果表示为<A,0>。将CS2作用于图10所示的thread1对应的线程内的CEG上,按照threadentry1调用函数C的顺序得到函数C的函数调用上下文对应的编码值为0。线程thread1内的函数C的函数调用上下文的编码结果可以表示为<C,0>。
S15:根据至少两个子链中的线程创建函数的函数调用上下文对应的编码结果确定该至少两个子链对应的线程之间的创建关系对应的编码值。
也就是根据第一子链中的每个子链中的线程创建函数的函数调用上下文对应的编码结果确定该函数调用链中的多个线程之间的创建关系对应的编码值。
如前所述,父线程内的线程创建函数的函数调用上下文的编码结果与父线程和子线程之间的创建关系对应的编码值是一一对应的。
例如,如图12所示,根据线程thread0内的函数A的函数调用上下文的编码结果表示为<A,0>确定thread0和thread1之间的创建关系对应的编码值为0。根据线程thread1内的函数C的函数调用上下文的编码结果表示为<C,0>确定thread1和thread2之间的创建关系对应的编码值为3。
S16:将该至少两个子链对应的线程之间的创建关系对应的编码值之和作为目标函数所属的线程的上下文的编码值。
例如,如图12所示,根据线程thread0内的函数A的函数调用上下文的编码结果表示为<A,0>确定thread0和thread1之间的创建关系对应的编码值为0。根据线程thread1内的函数C的函数调用上下文的编码结果表示为<C,0>确定thread1和thread2之间的创建关系对应的编码值为3。目标函数D所属的线程的上下文的编码值为3。
S17:根据函数调用链中尾端的子链中的线程入口函数和目标函数所属的线程的上下文的编码值确定目标函数所属的线程的上下文的编码结果。
目标函数所属的线程的上下文的编码结果可以表示为<第一元素,第二元素>,或者,也可以表示为<第五元素>。
例如,threadentry0→A→threadentry1→C→threadentry2→D中,尾端的子链CS3为threadentry2→D,其中的线程入口函数为threadentry2,目标函数D所属的线程的上下文 的编码结果可以表示为<threadentry2,3>。
进一步地,在函数调用链不包括线程创建函数所创建的线程入口函数的情况下,根据该函数调用链中的多个函数之间的调用关系对应的编码值确定目标函数在所属线程内的函数调用上下文的编码值;根据目标函数和目标函数在所属线程内的函数调用上下文的编码值确定目标函数在所属线程内的函数调用上下文的编码结果。
在函数调用链包括线程创建函数所创建的线程入口函数的情况下,根据该函数调用链中的线程创建函数确定目标函数所属的线程;根据目标函数所属的线程中的多个函数之间的调用关系对应的编码值确定目标函数在所属线程内的函数调用上下文对应的编码值;根据目标函数和目标函数在所属线程内的函数调用上下文的编码值确定目标函数在所属线程内的函数调用上下文的编码结果。
确定目标函数在所属线程内的函数调用上下文对应的编码值的方式可以根据需要设置,满足目标函数在所属线程内的不同函数调用上下文的编码值不同即可。
示例性地,将目标函数所属的线程中的多个函数之间的调用关系对应的编码值求和后的结果作为目标函数在所属线程内的函数调用上下文对应的编码值。例如,如图7中的一条函数调用链CS为threadentry0→A→threadentry1→C→threadentry2→D,目标函数D所属的线程为thread2,该线程内的多个函数之间的调用关系对应的编码值包括:threadentry2→D对应的编码值0,将0作为函数D在所属线程内的函数调用上下文的编码值。
示例性地,目标函数在所属线程内的函数调用上下文的编码结果可以表示为<第三元素,第四元素>的形式。其中的第三元素为目标函数,第四元素为目标函数在所属线程内的函数调用上下文的编码值。
步骤S770可以包括:在该函数调用链不包括线程创建函数所创建的线程入口函数的情况下执行步骤S18和步骤S19。在该函数调用链包括线程创建函数所创建的线程入口函数的情况下执行步骤S110步骤S111。
S18:根据多个线程内的多个函数之间的调用关系对应的编码值确定该函数调用链中的多个函数之间的调用关系对应的编码值。
示例性地,将该函数调用链作用于该函数调用链对应的线程内的CEG中,得到函数调用链中的多个函数之间的调用关系对应的编码值。
如图7中的一条函数调用链CS为threadentry0→A,该CS中不包括由线程创建函数所创建的线程入口函数,函数A所属的线程为thread0。例如,在如图10所示的线程内的CEG中,该函数调用链中的多个函数之间的调用关系对应的编码值即为threadentry0调用函数A对应的编码值0。
S19:根据该函数调用链中的多个函数之间的调用关系对应的编码值确定目标函数在所属线程内的函数调用上下文的编码结果。
示例性地,将该函数调用链中的多个函数之间的调用关系对应的编码值之和作为目标函数在所属线程内的函数调用上下文的编码值。也就是将该函数调用链作用于该函数调用链对应的线程内的CEG中,按照函数调用数据叠加该线程内的CEG中的对应的边上的编码值,得到目标函数在所属线程内的函数调用上下文的编码值。
进一步地,将目标函数在所属线程内的函数调用上下文的编码结果表示为<第三元素, 第四元素>。
例如,根据该函数调用链threadentry0→A中的多个函数之间的调用关系对应的编码值确定函数A在所属线程内的函数调用上下文的编码值为0。函数A在所属线程内的函数调用上下文的编码结果为<A,0>。
S110:多个线程内的多个函数之间的调用关系对应的编码值确定该函数调用链中尾端的子链中的多个函数之间的函数调用关系对应的编码值。
该子链是由步骤S12得到的。函数调用链中尾端的子链对应的线程即为目标函数所属的线程。
示例性地,将该尾端的子链作用于该尾端的子链对应的线程内的CEG中,得到尾端的子链中的多个函数之间的调用关系对应的编码值。
如图7中的一条函数调用链CS为threadentry0→A→threadentry1→C→threadentry2→D,由步骤S12得到的三个子链包括:CS1为threadentry0→A,CS2为threadentry1→C,CS3为threadentry2→D。基于如图10所示的线程内的CEG得到CS3中的多个函数之间的调用关系对应的编码值。threadentry2调用函数D对应的编码值为0。
S111:根据该尾端的子链中的多个函数之间的调用关系对应的编码值确定目标函数在所属线程内的函数调用上下文的编码结果。
示例性地,将该尾端的子链中的多个函数之间的调用关系对应的编码值之和作为目标函数在所属线程内的函数调用上下文的编码值。也就是将该尾端的子链作用于该函数调用链对应的线程内的CEG中,按照函数调用关系叠加该线程内的CEG中的对应的边上的编码值,得到目标函数在所属线程内的函数调用上下文的编码值。
例如,将前述CS3作用于图10所示的thread2对应的线程内的CEG上,按照threadentry2调用函数D的顺序得到函数D的函数调用上下文对应的编码值为0,函数D在线程thread2内的函数调用上下文的编码结果表示为<D,0>。
方式1中的编码方法可以称为基础编码方法。根据方式1中的编码方法能够由函数调用链得到目标函数的调用上下文的编码。
如前所述,本申请实施例的方法还包括提供API。下面举例说明方式1提供的API的形式。
(1)API1<线程入口函数,encoding0,目标函数,encoding1>=getencoding(callstring)
API1用于获取函数调用链的编码结果。API1的输入包括函数调用链。也就是说,通过API1获取的目标函数的调用上下文信息为函数调用链。函数调用链的编码结果即为目标函数的调用上下文的编码结果。目标函数的调用上下文的编码结果包括目标函数所属的线程的上下文的编码结果和目标函数在所属线程内的函数调用上下文的编码结果。API1的输出包括目标函数的调用上下文的编码结果。也就是说,得到目标函数的调用上下文的编码结果后,可以通过API1返回该四元组。
API1的四元组中的线程入口函数指的是目标函数所属的线程的线程入口函数,encoding0指的是目标函数所属的线程的上下文的编码值,目标函数即为该函数调用链所调用的函数,encoding1指的是目标函数在所属线程内的函数调用上下文的编码值。
需要说明的是,本申请实施例中的API输出的函数可以通过函数名表示,或者也可以通过函数的内存地址表示,本申请实施例对函数的表示形式不做限定,只要能够指示相应 的函数即可。API输出的编码值可以通过数值表示,或者也可以通过对应编码值的内存地址表示,本申请实施例对编码值的表示形式不做限定,只要能够指示相应的编码值即可。
(2)API2<X,目标函数,encoding1>=getencoding(callstring)
API2用于获取函数调用链的编码结果。API1的输入包括函数调用链。也就是说,通过API2获取的目标函数的调用上下文信息为函数调用链。函数调用链的编码结果即为目标函数的调用上下文的编码结果。目标函数的调用上下文的编码结果包括目标函数所属的线程的上下文的编码结果和目标函数在所属线程内的函数调用上下文的编码结果。API2的输出包括目标函数的调用上下文的编码结果。也就是说,得到目标函数的调用上下文的编码结果后,可以通过API2返回该三元组。
API2的三元组中的X用于指示目标函数所属的线程的线程入口函数和目标函数所属的线程的上下文的编码值,目标函数即为该函数调用链所调用的函数,encoding1指的是目标函数在所属线程内的函数调用上下文的编码值。也就是说<X>可以理解对<线程入口函数,encoding0>的一种包装,X和线程入口函数,encoding0之间存在对应关系。
示例性地,X可以表示为字符串或者数字等形式,本申请实施例对X的表示形式不做限定,只要与<线程入口函数,encoding0>一一对应即可,即X能够唯一指示<线程入口函数,encoding0>即可。
方式2
在一种实现方式中,目标函数的调用上下文信息包括:目标函数的调用者函数的调用上下文的编码结果和第一指令。
在一种实现方式中,目标函数的调用者函数也可以理解为当前函数,目标函数即为当前函数通过第一指令调用的函数。例如,在静态程序分析的过程中,分析器可以对每条指令逐条进行分析。当前分析器分析的指令所在的函数可以理解为当前函数,当分析至当前函数中的第一指令时转入目标函数中进行分析。
若第一指令为函数调用指令,则目标函数所属的线程为该调用者函数所属的线程。目标函数在所属线程内的函数调用上下文即为以该调用者函数所属的线程的线程入口函数为调用起点的函数调用上下文。若第一指令为线程创建指令,则目标函数所属的线程为该调用者函数所创建的线程,或者说,目标函数所属的线程为第一指令所创建的线程。目标函数在所属线程内的函数调用上下文即为以该调用者函数所创建的线程的线程入口函数为调用起点的函数调用上下文。如图7所示的CG中,一个调用者函数为函数B,第一指令为线程创建语句,目标函数为该线程创建语句所创建的线程入口函数,即threadentry2。函数threadentry2所属的线程即为线程入口函数threadentry2对应的线程thread2。目标函数D在所属线程内的函数调用上下文以目标函数D为起点。再如,一个调用者函数为threadentry1,第一指令为调用函数B,则目标函数为函数B,函数B所在的线程即为函数threadentry1所属的线程,若函数threadentry1所属的进程为thread1,则函数B所属的线程为thread1。目标函数B在所属线程内的函数调用上下文以thread1中的线程入口函数threadentry1为起点。
示例性地,目标函数所属的线程的上下文的编码结果可以表示为<第一元素,第二元素>的形式。其中的第一元素为目标函数所属的线程的线程入口函数,第二元素为目标函数所属的线程的上下文的编码值。或者,目标函数所属的线程的上下文的编码结果可以表 示为<第五元素>的形式,其中第五元素表示对线程入口函数和线程编码值的一种包装,即<第五元素>和<第一元素,第二元素>之间具有对应关系,第五元素能够用于指示目标函数所属的线程的上下文的编码值和目标函数所属的线程的线程入口函数。例如,第五元素可以为字符串或数字等形式。
可选地,步骤S750包括:在第一指令为函数调用指令的情况下,执行步骤S21。在第一指令为线程创建指令的情况下执行步骤S22至步骤S24。
S21:将调用者函数所属的线程的上下文的编码结果作为目标函数所属的线程的上下文的编码结果。
例如,调用者函数的调用上下文的编码结果为<threadentry1,0,threadentry1,0>,第一指令为调用函数B。调用者函数所属的线程的上下文的编码结果为<threadentry1,0>,第一指令为函数调用指令。目标函数B的所属的线程的上下文的编码结果为<threadentry1,0>。
S22:根据调用者函数在所属线程内的函数调用上下文的编码结果确定调用者函数所属线程和目标函数所属线程之间的创建关系对应的编码值。
由于第一指令为线程创建语句,调用者函数为线程创建函数。如前所述,父线程和子线程之间的创建关系对应的编码值与父线程中的线程创建函数在父线程内的函数调用上下文的编码结果对应。调用者函数即为父线程中的线程创建函数,目标函数所属的线程即为子线程。
例如,调用者函数的调用上下文的编码结果为<threadentry1,0,B,1>,第一指令为线程创建语句,用于创建线程入口函数threadentry2。调用者函数为函数B,目标函数为threadentry2。调用者函数在所属线程内的函数调用上下文的编码结果为<B,1>,根据<B,1>在如图11所示的TEG中确定thread1和thread2之间的创建关系对应的编码值为1。thread1为调用者函数所属线程,thread2为目标函数所属线程。
S23:将调用者函数所属的线程的上下文的编码值以及调用者函数所属线程和目标函数所属线程之间的创建关系对应的编码值之和作为目标函数所属的线程的上下文的编码值。
其中,步骤S23中还可以根据其他方式确定目标函数所属的线程的上下文的编码值,满足线程的不同上下文的编码值不同即可。
例如,调用者函数的调用上下文的编码结果为<threadentry1,0,B,1>,第一指令为线程创建语句,用于创建线程入口函数threadentry2。调用者函数所属的线程的上下文的编码值为0。根据步骤S22得到thread1和thread2之间的创建关系对应的编码值为1。目标函数所属的线程的上下文的编码值为1。
S24:根据目标函数和目标函数所属的线程的上下文的编码值确定目标函数所属的线程的上下文的编码结果。
第一指令为线程创建语句,也就是说目标函数为该线程创建语句创建的线程入口函数,即目标函数自身为所属的线程的线程入口函数。
目标函数所属的线程的上下文的编码结果可以表示为<第一元素,第二元素>,或者,也可以表示为<第五元素>。
例如,调用者函数的调用上下文的编码结果为<threadentry1,0,B,1>,第一指令为 线程创建语句,用于创建线程入口函数threadentry2。目标函数为threadentry2,目标函数所属的线程的上下文的编码结果可以表示为<threadentry2,1>。
进一步地,在第一指令为函数调用指令的情况下,根据调用者函数与目标函数之间的调用关系确定在目标函数所属线程内的调用者函数与目标函数之间的调用关系对应的编码值,根据目标函数所属线程内的调用者函数与目标函数之间的调用关系对应的编码值和调用者函数在所属线程内的函数调用上下文的编码结果确定目标函数在所属线程内的函数调用上下文的编码结果。
在第一指令为线程创建指令的情况下,目标函数自身为目标函数所属线程的线程入口函数。对目标函数在线程内的函数调用上下文进行编码,得到目标函数在线程内的函数调用上下文的编码结果。例如,作为线程内的调用起点的函数的函数调用上下文编码值可以设置为0,则目标函数在所属线程内的函数调用上下文的编码结果包括目标函数和该编码值。
示例性地,目标函数在所属线程内的函数调用上下文的编码结果可以表示为<第三元素,第四元素>的形式。其中的第三元素为目标函数,第四元素为目标函数在所属线程内的函数调用上下文的编码值。
步骤S770可以包括:在第一指令为函数调用指令的情况下执行步骤S25至步骤S27。在第一指令为线程创建指令的情况下执行步骤S28。
S25:根据第一指令确定在目标函数所属线程内的调用者函数与目标函数之间的调用关系对应的编码值。
其中,第一指令用于指示调用者函数与目标函数之间的调用关系。线程内的调用者函数与目标函数之间的调用关系对应的编码值也可以理解为线程内第一指令对应的编码值。
示例性地,将第一指令作用于目标函数所属线程内的CEG中,得到该线程内的第一指令对应的编码值。
例如,调用者函数的调用上下文的编码结果为<threadentry1,0,threadentry1,0>,第一指令为调用函数B。在目标函数B所属的线程thread1内的CEG中,第一指令对应的编码值可以为1。
S26:根据目标函数所属线程内的调用者函数与目标函数之间的调用关系对应的编码值以及调用者函数在所属线程内的函数调用上下文的编码值确定目标函数在所属线程内的函数调用上下文的编码值。
示例性地,将目标函数所属线程内的调用者函数与目标函数之间的调用关系对应的编码值以及调用者函数在所属线程内的函数调用上下文的编码值之和作为目标函数在所属线程内的函数调用上下文的编码值。
例如,调用者函数的调用上下文的编码结果为<threadentry1,0,threadentry1,0>,调用者函数在所属线程内的函数调用上下文的编码值为0,根据步骤S25得到第一指令对应的编码值为1,目标函数B在所属线程内的函数调用上下文的编码值即为1。
S27:根据目标函数在所属线程内的函数调用上下文的编码值和目标函数确定目标函数在所属线程内的函数调用上下文的编码结果。
例如,步骤S26得到目标函数B在所属线程内的函数调用上下文的编码值为1,将目标函数B在所属线程内的函数调用上下文的编码结果表示为<B,1>。
S28:将目标函数作为目标函数所属线程的线程入口函数,确定目标函数在所属线程内的函数调用上下文的编码结果。
例如,调用者函数的调用上下文的编码结果为<threadentry1,0,B,1>,第一指令为线程创建语句,用于创建线程入口函数threadentry2。threadentry2即为thread2的线程入口函数。目标函数为threadentry2,确定threadentry2在所属线程thread2内的函数调用上下文的编码值为0,目标函数在所属线程内的函数调用上下文的编码结果可以表示为<threadentry2,0>。
方式2中编码方法可以称为进阶编码方法。根据方式2中的方法能够由调用者函数的调用上下文的编码结果和第一指令得到目标函数的调用上下文的编码。
如前所述,本申请实施例的方法还包括提供API。下面举例说明方式2提供的API的形式。
API3En=getSuccEncoding(En’,第一指令)
其中En表示目标函数的调用上下文的编码结果,En’表示目标函数的调用者函数的调用上下文的编码结果。例如,编码结果可以以API1或API2提供的输出的形式表示。
在一种实现方式中,目标函数的调用者函数也可以理解为当前函数,目标函数即为当前函数通过第一指令调用的函数。
API3用于获取目标函数的调用上下文的编码结果。API3的输入包括调用者函数的调用上下文的编码结果和第一指令。也就是说,通过API3获取的目标函数的调用上下文包括调用者函数的调用上下文的编码结果和第一指令。目标函数的调用上下文的编码结果包括目标函数所属的线程的上下文的编码结果和目标函数在所属线程内的函数调用上下文的编码结果。API3的输出包括目标函数的调用上下文的编码结果。也就是说,得到目标函数的调用上下文的编码结果后,可以通过API3返回该编码结果。返回结果的形式可以参考API1或API2,详细描述参见前文中API1或API2的描述,此处不再赘述。
方式3
在一种实现方式中,目标函数的调用上下文信息包括:被目标函数调用的被调函数的调用上下文的编码结果和第二指令。
在一种实现方式中,被目标函数调用的被调函数也可以理解为当前函数,当前函数即为目标函数通过第二指令调用的函数。例如,在静态分析的过程中,分析器可以对每条指令逐条进行分析。当前分析器分析的指令所在的函数可以理解为当前函数,在当前函数分析结束后,根据第二指令可以转回调用当前函数的函数,即目标函数,继续进行分析。
若第二指令为函数调用指令,则目标函数所属的线程为该被调函数所属的线程。目标函数在所属线程内的函数调用上下文即为以该被调函数所属的线程的线程入口函数为调用起点的函数调用上下文。若第二指令为线程创建指令,则目标函数所属的线程为创建该被调函数的线程,或者说,被调函数所属的线程为第二指令所创建的线程。目标函数所属的线程为被调函数所属的线程的父线程。目标函数在所属线程内的函数调用上下文即为以该目标函数所属线程的线程入口函数为调用起点的函数调用上下文。如图7所示的CG中,一个被调函数为函数B,第二指令为函数调用语句,用于指示函数threadentry1调用函数B,则目标函数为函数threadentry1。函数threadentry1所属的线程即为函数B所属的线程,若函数B所属的进程为thread1,则函数threadentry1所属的线程为thread1。目标函数 threadentry1在所属线程内的函数调用上下文以thread1中的线程入口函数threadentry1为起点。再如,一个被调函数为函数threadentry2,第二指令为线程创建语句,用于指示函数B创建函数threadentry2。则目标函数为函数B。函数B所属的线程为函数threadentry2所属线程的父线程thread1。目标函数B在所属线程内的函数调用上下文以thread1的线程入口函数为起点。
示例性地,目标函数所属的线程的上下文的编码结果可以表示为<第一元素,第二元素>的形式。其中的第一元素为目标函数所属的线程的线程入口函数,第二元素为目标函数所属的线程的上下文的编码值。或者,目标函数所属的线程的上下文的编码结果可以表示为<第五元素>的形式,其中第五元素表示对线程入口函数和线程编码值的一种包装,即<第五元素>和<第一元素,第二元素>之间具有对应关系,第五元素能够用于指示目标函数所属的线程的上下文的编码值和目标函数所属的线程的线程入口函数。例如,第五元素可以为字符串或数字等形式。
可选地,步骤S750包括:在第二指令为函数调用指令的情况下,执行步骤S31。在第二指令为线程创建指令的情况下执行步骤S32至步骤S34。
S31:在第二指令为函数调用指令的情况下,将被调函数所属的线程的上下文的编码结果作为目标函数所属的线程的上下文的编码结果。
例如,被调函数的调用上下文的编码结果为<threadentry1,0,B,1>,第二指令用于指示函数threadentry1调用函数B。被调函数B所属的线程的上下文的编码结果为<threadentry1,0>,第二指令为函数调用指令。目标函数threadentry1的所属的线程的上下文的编码结果为<threadentry1,0>。
S32:根据被调函数所属的线程的上下文的编码结果确定目标函数所属线程和被调函数所属线程之间的创建关系对应的编码值。
示例性地,将被调函数所属的线程的上下文的编码结果作用于TEG中,得到目标函数所属线程和被调函数所属线程之间的创建关系对应的编码值。
例如,被调函数的调用上下文的编码结果为<threadentry2,1,threadentry2,0>,第二指令为线程创建语句,用于指示创建线程入口函数threadentry2。被调函数所属的线程的上下文的编码结果为将编码结果<threadentry2,1>,将该编码结果作用于TEG中,得到编码值1指示的唯一一条被调函数所属的线程的上下文。即thread0与thread1之间的创建关系对应的编码值为0,thread1和thread2之间的创建关系对应的编码值为1,两者之和为1。
S33:将被调函数所属的线程的上下文的编码值与目标函数所属线程和被调函数所属线程之间的创建关系对应的编码值之差作为目标函数所属的线程的上下文的编码值。
其中,步骤S33中还可以根据其他方式确定目标函数所属的线程的上下文的编码值,满足线程的不同上下文的编码值不同即可。
例如,被调函数的调用上下文的编码结果为<threadentry2,1,threadentry2,0>,第二指令为线程创建语句,用于创建线程入口函数threadentry2。被调函数所属的线程的上下文的编码值为1。根据步骤S32得到thread1和thread2之间的创建关系对应的编码值为1。目标函数所属的线程的上下文的编码值为0。
S34:根据目标函数所属线程的线程入口函数和目标函数所属的线程的上下文的编码 值确定目标函数所属的线程的上下文的编码结果。
目标函数所属的线程的上下文的编码结果可以表示为<第一元素,第二元素>,或者,也可以表示为<第五元素>。
例如,被调函数的调用上下文的编码结果为<threadentry2,1,threadentry2,0>,第二指令为线程创建语句,用于创建线程入口函数threadentry2。目标函数为函数B,在图11所示的TEG中,目标函数所属的线程的线程入口函数为threadentry1。目标函数所属的线程的上下文的编码结果可以表示为<threadentry1,0>。
进一步地,在第二指令为函数调用指令的情况下,根据被调函数与目标函数之间的调用关系确定在目标函数所属线程内的被调函数与目标函数之间的调用关系对应的编码值,根据目标函数所属线程内的被调函数与目标函数之间的调用关系对应的编码值和被调函数在所属线程内的函数调用上下文的编码结果确定目标函数在所属线程内的函数调用上下文的编码结果。
在第二指令为线程创建指令的情况下,目标函数即为被调函数所属线程的线程创建函数。或者说,目标函数即为父线程中的线程创建函数。父线程中的线程创建函数在父线程内的函数调用上下文的编码结果与父线程和子线程之间的创建关系对应的编码值是一一对应的。根据被调函数所属的线程的上下文的编码结果确定目标函数所属线程和被调函数所属线程之间的创建关系对应的编码值,进而根据目标函数所属线程和被调函数所属线程之间的创建关系对应的编码值确定目标函数在所属线程内的函数调用上下文的编码结果。
示例性地,目标函数在所属线程内的函数调用上下文的编码结果可以表示为<第三元素,第四元素>的形式。其中的第三元素为目标函数,第四元素为目标函数在所属线程内的函数调用上下文的编码值。
步骤S770可以包括:在第二指令为函数调用指令的情况下执行步骤S35至步骤S37。在第二指令为线程创建指令的情况下执行步骤S38。
S35:根据第二指令确定在目标函数所属线程内的被调函数与目标函数之间的调用关系对应的编码值。
其中,第二指令用于指示被调函数与目标函数之间的调用关系。线程内的被调函数与目标函数之间的调用关系对应的编码值也可以理解为线程内第二指令对应的编码值。
示例性地,将第二指令作用于目标函数所属线程内的CEG中,得到该线程内的第二指令对应的编码值。
例如,被调函数的调用上下文的编码结果为<threadentry1,0,B,1>,第二指令为调用函数B。在目标函数threadentry1所属的线程thread1内的CEG中,第二指令对应的编码值可以为1。
S36:根据目标函数所属线程内的被调函数与目标函数之间的调用关系对应的编码值以及被调函数在所属线程内的函数调用上下文的编码值确定目标函数在所属线程内的函数调用上下文的编码值。
示例性地,将被调函数在所属线程内的函数调用上下文的编码值和目标函数所属线程内的被调函数与目标函数之间的调用关系对应的编码值之差作为目标函数在所属线程内的函数调用上下文的编码值。
例如,被调函数的调用上下文的编码结果为<threadentry1,0,B,1>,被调函数B在 所属线程内的函数调用上下文的编码值为1,根据步骤S35得到第二指令对应的编码值为1,目标函数threadentry1在所属线程内的函数调用上下文的编码值即为0。
S37:根据目标函数在所属线程内的函数调用上下文的编码值和目标函数确定目标函数在所属线程内的函数调用上下文的编码结果。
例如,步骤S36得到目标函数threadentry1在所属线程内的函数调用上下文的编码值为0,将目标函数threadentry1在所属线程内的函数调用上下文的编码结果表示为<threadentry1,0>。
S38:根据目标函数所属线程和被调函数所属线程之间的创建关系对应的编码值确定目标函数在所属线程内的函数调用上下文的编码结果。
如前所述,目标函数所属线程为被调函数所属线程的父线程,第二指令为线程创建语句,目标函数即为父线程中线程创建函数。父线程中的线程创建函数在父线程内的函数调用上下文的编码结果与父线程和子线程之间的创建关系对应的编码值是一一对应的。根据该对应关系可以确定步骤S32得到的编码值对应的目标函数在所属线程内的函数调用上下文的编码结果。
例如,步骤S32得到thread1和thread2之间的创建关系对应的编码值为1,根据父线程和子线程之间的创建关系对应的编码值和父线程中的线程创建函数的函数调用上下文的编码结果之间的对应关系,得到该编码值对应的线程创建函数的函数调用上下文的编码结果为<B,1>。目标函数在所属线程内的函数调用上下文的编码结果可以表示为<B,1>。
在另一种实现方式中,目标函数的调用上下文信息包括:被目标函数调用的被调函数的调用上下文的编码结果。
根据该被调函数的调用上下文的编码结果可以得到第二指令对应的编码值和目标函数的调用上下文的编码结果。
被调函数的调用上下文的编码结果用于指示被调函数所属线程的上下文的编码值、被调函数所属线程的线程入口函数、被调函数在所属线程内的函数调用上下文的编码值以及被调函数。
若被调函数所属线程的线程入口函数和被调函数不同,则第二指令为函数调用指令。目标函数所属的线程即为被调函数所属的线程。目标函数在所属线程内的函数调用上下文即为以该被调函数所属的线程的线程入口函数为调用起点的函数调用上下文。
若被调函数所属线程的线程入口函数和被调函数相同,也就是说,被调函数即为所属线程的线程入口函数,则第二指令为线程创建指令,则目标函数所属的线程为创建该被调函数的线程,或者说,被调函数所属的线程为第二指令所创建的线程。目标函数所属的线程为被调函数所属的线程的父线程。目标函数在所属线程内的函数调用上下文即为以该目标函数所属线程的线程入口函数为调用起点的函数调用上下文。
步骤S750的具体描述可以参见前述方式3中的步骤S31至步骤S34,此处不再赘述。
进一步地,步骤S770可以包括:在第一指令为函数调用指令的情况下执行步骤S45至步骤S47。在第一指令为线程创建指令的情况下执行步骤S48。
S45:根据被调函数在所属线程内的函数调用上下文的编码结果确定被调函数所属线程内的目标函数与被调函数之间的调用关系对应的编码值。
被调函数所属线程内的目标函数与被调函数之间的调用关系即为第二指令指示的调 用关系。
示例性地,步骤S45包括:根据被调函数在所属线程内的函数调用上下文的编码结果确定被调函数在所属线程内的函数调用上下文,进而确定被调函数所属线程内的目标函数与被调函数之间的调用关系对应的编码值。
由于被调函数在所属线程内的函数调用上下文的编码值与被调函数在所属线程内的函数调用上下文是一一对应的,因此,根据被调函数在所属线程内的编码结果即可得到被调函数在所属线程内的唯一一个函数调用上下文。
例如,被调函数在所属线程内的编码值为被调函数在所属线程内的函数调用上下文中的多个函数之间的调用关系对应的编码值之和。在该情况下,步骤S45可以理解为,在被调函数所属的线程内确定一条被调函数的函数调用上下文,其编码值等于被调函数在所属线程内的函数调用上下文中的多个函数之间的调用关系对应的编码值之和。比如,将根据被调函数在所属线程内的函数调用上下文的编码结果作用于线程内的CEG中,通过路径匹配即可得到被调函数在所属线程内的函数调用上下文,同时得到目标函数与被调函数之间的调用关系对应的编码值。
例如,被调函数的调用上下文的编码结果为<threadentry1,0,B,1>。被调函数在线程内的函数调用上下文的编码结果<B,1>,将<B,1>在目标函数threadentry1所属的线程thread1内的CEG中,可以得出被调函数所属线程内的目标函数与被调函数之间的调用关系对应的编码值为1。
可替换地,步骤S45包括:根据被调函数在所属线程内的函数调用上下文的编码值与线程内的该被调函数的所有调用者函数与该被调函数之间的调用关系对应的编码值之间的差值确定被调函数所属线程内的目标函数与被调函数之间的调用关系对应的编码值。
步骤S720中可以采用调用上下文编码算法对线程内的多个函数之间的调用关系进行编码,在一种实现方式中,通过该编码方式可以使得函数在线程内数的函数调用上下文的编码值小于线程内的函数的调用上下文的数量,且线程内数的函数调用上下文的编码值大于或等于0的整数。例如,图10中,函数B在thread1中的函数调用上下文包括两个,两个函数调用上下文的编码值分别为0和1。在该情况下,可以将被调函数在所属线程内的函数调用上下文的编码值与线程内的该被调函数的所有调用者函数与该被调函数之间的调用关系对应的编码值相减,得到满足条件的差值,根据该差值得到的调用关系对应的编码值即为被调函数所属线程内的目标函数与被调函数之间的调用关系对应的编码值。满足条件的差值指的是该差值大于或等于0,且该差值小于线程内的该差值对应的调用者函数的函数调用上下文的数量,或者该差值为0,且该差值对应的调用者函数的函数调用上下文的数量为0。
例如,被调函数在线程内的函数调用上下文的编码结果<B,1>。如图10所示,线程内的该被调函数的所有调用者函数与该被调函数之间的调用关系包括threadentry1对函数B的两次调用关系,该两次调用关系对应的编码值分别为0和1。将被调函数B在线程内的函数调用上下文的编码值1分别与0和1相减,得到两个差值1和0。调用者函数的函数调用上下文的数量为0,其中差值0满足上述条件,该差值对应的调用关系为编码值1对应的调用关系,由此得到,被调函数所属线程内的目标函数与被调函数之间的调用关系对应的编码值为1。
应理解,以上仅为示例,还可以通过其他方式根据确定被调函数所属线程内的目标函数与被调函数之间的调用关系对应的编码值。
步骤S46至步骤S48可以分别参照前述步骤S36至步骤S38,此处不再赘述。
进一步地,方法700还可以包括:
获取第二指令,根据目标函数在所属线程内的函数调用上下文的编码结果确定第二指令是否准确。
如前所述,方式3中的目标函数的调用上下文信息可以仅包括被调函数的调用上下文的编码结果。也就是说,方式3中可以不使用第二指令得到目标函数的调用上下文的编码结果。编码结果可以用于验证第二指令是否准确。例如,若目标函数在所属线程内的函数调用上下文的编码值与被调函数在所属线程内的函数调用上下文的编码值之差等于第二指令所指示的调用关系对应的编码值,则第二指令准确,否则,第二指令错误。应理解,此处仅为示例,还可以通过其他方式基于目标函数在所属线程内的函数调用上下文的编码结果验证第二指令是否准确。
方式3中编码方法可以称为进阶编码方法。根据方式3中的方法能够由被调函数的调用上下文的编码结果得到目标函数的调用上下文的编码。
如前所述,本申请实施例的方法还包括提供API。下面举例说明方式3提供的API的形式。
API4En=getPredEncoding(En’,第二指令)
可替换地,API4En=getPredEncoding(En’)
其中En表示目标函数的调用上下文的编码结果,En’表示被目标函数调用的被调函数的调用上下文的编码结果。例如,编码结果可以以API1或API2提供的输出的形式表示。
在一种实现方式中,被调函数也可以理解为当前函数,当前函数即为目标函数通过第二指令调用的函数。
API4用于获取目标函数的调用上下文的编码结果。API4的输入包括被调函数的调用上下文的编码结果。或者,API4的输入包括被调函数的调用上下文的编码结果和第二指令。也就是说,通过API4获取的目标函数的调用上下文至少包括被调函数的调用上下文的编码结果。目标函数的调用上下文的编码结果包括目标函数所属的线程的上下文的编码结果和目标函数在所属线程内的函数调用上下文的编码结果。API4的输出包括目标函数的调用上下文的编码结果。也就是说,得到目标函数的调用上下文的编码结果后,可以通过API4返回该编码结果。返回结果的形式可以参考API1或API2,详细描述参见前文中API1或API2的描述,此处不再赘述。
表1示出了本申请实施例的编码方法和函数调用链的方式在内存开销上的对比结果。
表1
表1中的N和M为正整数。由表1可以看出,callsting的字节占有量随着callstring的长度的增大而增大,当程序代码较大时,通过callstring表示函数的调用上下文所需的字节数大大超过本申请实施例中的编码结果所述的字节数。因此,相较于通过callstring表示函数的调用上下文的方法,本申请实施例中的编码方法能够明显减少内存开销。
为了更清楚地说明本申请实施例的应用场景,下面结合静态程序分析中的三个应用场景(场景1、场景2和场景3)对本申请实施例中的方案进行说明。
场景1:变量上下文的表示
变量的上下文表示涉及各种类型的变量,本申请实施例中以malloc指针分配的变量作为场景1的示例,分析的源码如下所示。
main函数在两个不同的位置创建了子线程sub_thread;sub_thread会返回malloc指针地址空间,my_molloc函数返回堆上分配的内存地址给p,若指针分析需要区分第一次调用call1和第二次调用call2两处指针p指向不同的内存地址,则分析工具需要区别两个子线程调用的my_molloc函数的调用上下文。若采用函数调用链的方式表达my_molloc函数的调用上下文,则两次调用的my_molloc函数的调用上下文分别表示为两个函数调用链:main→sub_thread1→my malloc和main→sub_thread2→my malloc。通过函数调用链表示函数的调用上下文会增加内存开销。
本申请实施例中的方法能够对函数的调用上下文进行编码,以函数的调用上下文的编码结果表示函数的调用上下文,减少保存函数的上下文带来的内存开销。
具体地,分析器由根函数开始逐条分析每条指令,并对该指令所在的函数的调用上下文进行编码。在分析器分析当前函数的过程中,分析至call1时,可以采用方式2中的编码方式,基于当前函数的编码结果和call1得到本次调用my_molloc函数的调用上下文的编码结果,并保存该编码结果,转入my_molloc函数中进行分析。当分析器在my_molloc函数分析结束后,可以采用方式3中的编码方式,基于my_molloc函数的编码结果和call1得到调用my_molloc函数的调用者函数的调用上下文的编码结果,继续执行分析。在分析至call2时可以采用相同的方式得到本地调用的my_molloc函数的调用上下文的编码结果。这样,可以区分两次调用my_molloc函数时my_molloc函数的不同的调用上下文。例如,对于一个malloc变量的调用上下文的编码结果可以表示为<线程入口函数,encoding0,mymalloc,encoding1>:malloc。malloc表示一个实体名。这样,能够区分两个线程中的的my_molloc函数的调用上下文,显著减少保存函数的上下文带来的内存开销,提高分析精度和分析效率。
场景2:互斥锁分析
互斥锁分析是多线程分析中必要的分析之一,用于区别互斥锁保护的程序语句范围。 或者说互斥锁分析用于区分指令是否被锁保护。若不区分函数的调用上下文,则仅记录一条指令所在的函数的位置。由于同一指令在程序中可能被调用多次,若在该多次调用中的几次调用中,该指令被锁保护,其他调用中,该指令没有被锁保护,在仅记录该指令所在的函数的位置的情况下,分析器仅能返回该指令所在函数的位置,无法准确返回该指令是否被锁保护,具体返回结果为该指令既被锁保护又没有锁保护。
若区分函数的调用上下文,则可以记录该指令所在函数的调用上下文,该指令每次被调用均对应函数的不同的调用上下文,分析器能够准确返回该指令所在的函数的调用上下文,进而准确给出在该函数的调用上下文中的指令是否被锁保护。
场景2中以如下源码为例进行互斥锁分析。
main函数顺序调用了my_func、pthread_lock(上互斥锁)、my_func、pthread_unlock(解互斥锁)。该互斥锁之间的my_func函数中的所有语句被互斥锁保护。也就是说,第一次调用my_func中的所有语句没有被互斥锁保护,第二次调用my_func中的所有语句被互斥锁保护。分析器通过两次调用my_func时my_func的不同调用上下文来表示两次调用的my_func中的指令的不同。若采用函数调用链的方式表达my_func函数的调用上下文,则两次调用的my_func函数的调用上下文分别表示为两个函数调用链: main→call1→my_func和main→call2→my_func。main→call1→my_func中的所有指令没有被互斥锁保护,main→call2→my_func中的所有指令被互斥锁保护。然而,通过函数调用链表示函数的调用上下文会增加内存开销。
本申请实施例中的方法能够对函数的调用上下文进行编码,以函数的调用上下文的编码结果表示函数的调用上下文,减少保存函数的上下文带来的内存开销。
可以采用方式2和方式3中的方式对my_func的调用上下文进行编码,得到函数的调用上下文的编码结果。具体描述可以参见场景1中的描述,此处不再赘述。对于一条指令,其所在函数my func的调用上下文的编码结果可以表示为<线程入口函数,encoding0,my func,encoding1>。进一步地,一条指令是否被锁保护可以表示为<线程入口函数,encoding0,my func,encoding1>:instruction→是否有锁保护。其中,instruction表示对该指令的描述。
此外,main函数调用了线程创建语句,创建了一个子线程,该子线程中顺序调用了pthread_lock(上互斥锁)、pthread_unlock(解互斥锁)。在该互斥锁之间的指令被互斥锁保护。
<线程入口函数,encoding0,my func,encoding1>的表示方式能够区分指令所在函数所属的线程的上下文信息。上述代码中,第二次调用的my func中的指令所属的线程和global_var所属的线程不同,通过上述编码方式无需解码即可得到函数所属的线程的上下文信息,能够对区分多线程中的函数的调用上下文。
场景3:可能并行分析
MHP分析是多线程分析中必要的分析之一,用于区别程序代码中的任两条语句是否可能并发执行。若不区分函数的调用上下文,则仅记录一条指令所在的函数的位置。由于同一指令在程序中可能被调用多次,若在该多次调用中的几次调用中,该指令与指令A可能并发执行,其他调用中,该指令与指令A不能并发执行,在仅记录该指令所在的函数的位置的情况下,分析器仅能返回该指令所在函数的位置,无法准确返回该指令是否能与指令A并发执行,具体返回结果为该指令既能与指令A并发执行,又不能与指令A并发执行。
若区分函数的调用上下文,则可以记录该指令所在函数的调用上下文,该指令每次被调用均对应函数的不同的调用上下文,分析器能够准确返回该指令所在的函数的调用上下文,进而准确给出在该函数的调用上下文中的指令是否能与其他指令并发执行。
场景3中以如下源码为例进行互斥锁分析。
例如,上述代码中,main函数顺序my_func、pthread_create(创建了子线程sub_thread)、my_func。
第一次调用my_func中的所有语句不可能与sub_thread中的语句并发执行,第二次调用my_func中的所有语句与sub_thread中的语句是并发执行关系。分析器通过两次调用my_func时my_func的不同调用上下文来表示两次调用的my_func中的指令的不同。若采用函数调用链的方式表达my_func函数的调用上下文,则两次调用的my_func函数的调用上下文分别表示为两个函数调用链:main→call1→my_func和main→call2→my_func。main→call1→my_func中的所有指令不可能与sub_thread中的语句并发执行,main→call2→my_func中的所有指令与sub_thread中的语句是并发执行关。然而,通过函数调用链表示函数的调用上下文会增加内存开销。
本申请实施例中的方法能够对函数的调用上下文进行编码,以函数的调用上下文的编码结果表示函数的调用上下文,减少保存函数的上下文带来的内存开销。
可以采用方式2和方式3中的方式对my_func的调用上下文进行编码,得到函数的调用上下文的编码结果。具体描述可以参见场景1中的描述,此处不再赘述。对于一条指令,其所在函数my func的调用上下文的编码结果可以表示为<线程入口函数,encoding0,my func,encoding1>。进一步地,一条指令与可能并发执行的语句集合之间的关系可以表示为<线程入口函数,encoding0,my func,encoding1>:instruction→可能并发执行的语句的集合。其中,instruction表示对该指令的描述。
同一线程中的语句不可能并发执行,不同线程中的语句有可能并发执行,因此,需要区分一条语句所属的线程。<线程入口函数,encoding0,my func,encoding1>的表示方式能够区分指令所在函数所属的线程的上下文信息,通过上述编码方式无需解码即可得到函数所属的线程的上下文信息,能够快速区分多线程中的函数的调用上下文,提高了分析效率和分析精度。
在程序分析或debug等需要区分函数的不同的调用上下文的场景中,可以通过本申请实施例中的方法700得到编码结果,并对程序代码进行分析,分析结果是基于编码结果表示的。例如,可以通过场景1、场景2或场景3中的形式表示分析结果。函数调用链能够显性表示函数的调用上下文,在一些场景中需要将编码结果解码为函数调用链。
在一种场景中,在将分析结果返回至用户时,通过函数调用链的方式表示分析结果能够提高分析结果的可读性。通过本申请实施例提供的解码方法能够对目标函数的调用上下文的编码结果进行解码,得到目标函数的函数调用链。进而以函数调用链的形式将分析结果显示给用户。
在另一种场景中,对同一个程序代码的不同的分析过程可能采用不同的方式表示函数的调用上下文执行。若其中一个分析过程采用方法700对函数的调用上下文进行编码,即在分析过程中以函数的调用上下文的编码结果的形式表示分析结果。通过本申请实施例提供的解码方法能够对目标函数的调用上下文的编码结果进行解码,得到目标函数的函数调用链。进而以函数调用链的形式为其他分析过程提供分析结果,即本申请实施例中的解码方法能够兼容其他分析方法。例如,如图4所示的静态程序分析中的四个分析过程所采用 的函数的不同上下文的表示方法可能相同,也可能不同。例如,其中的互斥锁分析模块采用方法700对函数的调用上下文进行编码,得到函数的调用上下文的编码结果,也就是以函数的调用上下文的编码结果表示函数的调用上下文。MHP分析模块采用函数的函数调用链表示函数的调用上下文,由于MHP分析模块需要调用互斥锁分析模块的分析结果,因此,根据本申请实施例提供的解码方法能够将互斥锁分析模块的分析结果以函数调用链的形式提供至MHP模块中。
图13示出了本申请实施例提供一种函数的调用上下文的解码方法1700,能够对本申请实施例中的编码方法700得到的编码结果进行解码,得到函数调用链。方法1700是与方法700相对应的解码方法,详细描述可以参见方法700,在介绍方法1700时做适当省略。
S1710,获取目标函数的调用上下文的编码结果。
目标函数的调用上下文的编码结果包括目标函数所属的线程的上下文的编码结果和目标函数在所属线程内的函数调用上下文的编码结果。
可选地,目标函数在所属线程内的函数调用上下文的编码结果用于指示目标函数以及目标函数在所属线程内的函数调用上下文的编码值。
可选地,目标函数所属的线程的上下文的编码结果用于表示目标函数所属的线程的线程入口函数以及目标函数所属的线程的上下文的编码值。
S1720,获取程序代码中的多个线程之间的创建关系对应的编码值。程序代码包括该目标函数。
示例性地,程序代码中的多个线程之间的创建关系对应的编码值可以是通过步骤S720得到。
可替换地,程序代码中的多个线程之间的创建关系对应的编码值可以是从其他模块或设备接收的。
程序代码中的多个线程包括父线程和子线程,父线程中的线程创建函数用于创建所述子线程,父线程和子线程之间的创建关系对应的编码值与父线程中的线程创建函数的函数调用上下文对应。
S1730,获取多个线程内的多个函数之间的调用关系对应的编码值。
示例性地,程序代码中的多个线程内的多个函数之间的调用关系对应的编码值可以是通过步骤S720得到的。
可替换地,程序代码中的多个线程内的多个函数之间的调用关系对应的编码值可以是从其他模块或设备接收的。
S1740,根据程序代码中的多个线程之间的创建关系对应的编码值和程序代码中的多个线程内的多个函数之间的调用关系对应的编码值对目标函数的调用上下文的编码结果进行解码,得到目标函数的函数调用链。
可选地,步骤S1740包括步骤S1741至步骤S1744。
S1741,根据程序代码中的多个线程之间的创建关系对应的编码值对目标函数所属的线程的上下文的编码结果进行解码,得到目标函数所属的线程的上下文中的多个线程之间的创建关系对应的编码值。
其中,目标函数所属的线程的上下文中的多个线程之间的创建关系对应的编码值之和 等于目标函数所属的线程的上下文的编码值,目标函数所属的线程是根据目标函数所属的线程中的线程入口函数确定的。
目标函数所属的线程的上下文指的是目标函数所属的线程被创建的路径。
也就是说,步骤S1741可以理解为根据程序代码中的多个线程之间的创建关系对应的编码值确定一个目标函数所属的线程的上下文,该上下文中的线程之间的创建关系对应的编码值之和等于目标函数所属的线程的上下文的编码值。该线程的上下文的终点为目标函数所属的线程,起点可以为主线程。
主线程指的是其线程入口函数为根函数的线程,根函数为程序代码中没有被其他函数调用的函数。在TEG图中,主线程指的是没有被其他线程指向的线程。
示例性地,将目标函数所属的线程的上下文的编码结果作用于TEG中,根据路径匹配得到目标函数所属的线程的上下文,即得到目标函数所属的线程的上下文中的多个线程之间的创建关系对应的编码值。
例如,目标函数的调用上下文的编码结果为<threadentry2,2,D,0>,其中,目标函数D所属的线程为线程入口函数threadentry2对应的线程thread2。将目标函数D所属的线程thread2的上下文的编码结果<threadentry2,0>作用于图11中的TEG中,得到目标函数所属的线程thread2的上下文为thread0创建thread1,thread1创建thread2,thread0和thread1之间的创建关系对应的编码值为0,thread1与thread2之间的创建关系对应的编码值为2。
需要说明的是,若根据程序代码中的多个线程之间的创建关系对应的编码值和目标函数所属的线程的上下文的编码结果确定目标函数所属的线程不是其他线程创建的,即目标函数所属的线程为主线程,直接执行步骤S1744,将步骤S1744中的线程内的函数调用链作为目标函数调用链。
S1742,根据目标函数所属的线程的上下文中的多个线程之间的创建关系对应的编码值确定目标函数所属的线程的上下文中的多个线程中的线程创建函数的函数调用上下文的编码结果。
例如,目标函数的调用上下文的编码结果为<threadentry2,2,D,0>,由步骤S1741得到thread0和thread1之间的创建关系对应的编码值0以及thread1与thread2之间的创建关系对应的编码值2。根据图12可以得出,thread0和thread1之间的创建关系对应的编码值0对应的thread0中的线程创建函数的函数调用上下文的编码结果为<A,0>;thread1与thread2之间的创建关系对应的编码值2对应的thread1中的线程创建函数的函数调用上下文的编码结果为<C,0>。
S1743,根据程序代码中的多个线程内的多个函数之间的调用关系对应的编码值对目标函数所属的线程的上下文中的多个线程中的线程创建函数的函数调用上下文的编码结果进行解码,得到线程创建函数在所属线程内的函数调用链。
其中,线程创建函数在所属线程内的函数调用链的调用起点为线程创建函数所属的线程的线程入口函数,线程创建函数在所属线程内的函数调用链的调用终点为线程创建函数。线程创建函数在所属线程内的函数调用链中的多个函数之间的调用关系对应的编码值之和等于线程创建函数在所属线程内的函数调用链的编码值。
线程创建函数在所属线程内的函数调用链的调用起点和线程创建函数在所属线程内 的函数调用链的调用终点通常不同。
线程创建函数可以为一个,也可以为多个。相应地,线程创建函数在所属线程内的函数调用链可以为一个,也可以为多个。
例如,thread0中的线程创建函数的函数调用上下文的编码结果为<A,0>,根据图10可以得出,线程创建函数A在thread0内的函数调用链为threadentry0→A。thread1中的线程创建函数的函数调用上下文的编码结果为<C,0>,根据图10可以得出,线程创建函数C在thread1内的函数调用链为threadentry1→C。
S1744,根据程序代码中的多个线程内的多个函数之间的调用关系对应的编码值对目标函数在所属线程内的函数调用上下文的编码结果进行解码,得到目标函数在所属线程内的函数调用链。
其中,目标函数在所属线程内的函数调用链的调用起点为目标函数所属的线程的线程入口函数,目标函数在所属线程内的函数调用链的调用终点为所述目标函数。
在目标函数在所属线程内的函数调用链的调用起点与目标函数在所属线程内的函数调用链的调用终点不同的情况下,目标函数在所属线程内的函数调用链中的多个函数之间的调用关系对应的编码值之和等于目标函数在所属线程内的函数调用上下文的编码值。
也就是说,步骤S1744可以理解为根据目标函数所属线程内的多个函数之间的调用关系对应的编码值确定一条线程内的以目标函数所属线程的线程入口函数为调用起点以目标函数为调用终点的函数调用链,该线程内的函数调用链中的函数之间的调用关系对应的编码值之和等于目标函数在所属线程内的函数调用上下文的编码值。
若在目标函数的调用上下文的编码结果中,目标函数所属的线程的线程入口函数和目标函数相同,即目标函数在所属线程内的函数调用链的调用起点与目标函数在所属线程内的函数调用链的调用终点相同,则目标函数在所属线程内的函数调用链即为目标函数自身。
示例性地,根据目标函数所属线程的线程入口函数即可得出目标函数所属的线程。将目标函数在所属线程内的函数调用上下文的编码结果作用于目标函数所属的线程内的CEG中,得到目标函数在所属线程内的函数调用链,即目标函数在所属线程内的函数调用上下文。
例如,目标函数的调用上下文的编码结果为<threadentry2,2,threadentry2,0>,则目标函数threadentry2在所属线程内的函数调用链为threadentry2自身。再如,目标函数的调用上下文的编码结果为<threadentry2,2,D,0>,其中,目标函数D所属的线程为线程入口函数threadentry2对应的线程thread2。将目标函数D在thread2内的函数调用上下文的编码结果<D,0>作用于图11中的thread2内的CEG中,得到目标函数在thread2内的函数调用链为threadentry2→D。
S1745,根据线程创建函数在所属线程内的函数调用链和目标函数在所属线程内的函数调用链确定目标函数的函数调用链。
具体地,将线程创建函数在第一线程内的函数调用链和目标函数在所属线程内的函数调用链按照步骤S1741中得到的目标函数所属的线程的上下文中的顺序组合得到目标函数的函数调用链。
例如,线程创建函数A在thread0内的函数调用链为threadentry0→A。线程创建函数C在thread1内的函数调用链为threadentry1→C。目标函数在thread2内的函数调用链为 threadentry2→D。将三者组合得到目标函数的函数调用链为threadentry0→A→threadentry1→C→threadentry2→D。
可选地,方法1700还包括提供第三API,该第三API的输入包括目标函数的调用上下文的编码结果。该第三API的输出包括目标函数的函数调用链。
或者也可以理解为,步骤S1710中目标函数的调用上下文的编码结果是通过第三API获取的。该第三API输出步骤S1740得到的目标函数的函数调用链。
第三API的输入的形式可以为四元组的形式,也就是说第三API的输入可以包括第一元素、第二元素、第三元素和第四元素,分别用于指示目标函数所属的线程中的线程入口函数、目标函数所属的线程的上下文编码值、目标函数以及目标函数在所属线程内的函数调用上下文的编码值。
可替换地,第三API的输入的形式可以为三元组的形式,也就是说第三API的输入可以包括第五元素、第六元素和第七元素,第五元素用于指示目标函数所属的线程中的线程入口函数和目标函数所属的线程的上下文编码值,第六元素用于指示目标函数,第七元素用于指示目标函数在所属线程内的函数调用上下文的编码值。
下面举例说明解码方法1700中提供的API的形式。
(1)API5callstring=getdecoding(<线程入口函数,encoding0,目标函数,encoding1>)
API5用于获取函数调用链。API5的输入包括目标函数的调用上下文的编码结果。目标函数的调用上下文的编码结果包括目标函数所属的线程的上下文的编码结果和目标函数在所属线程内的函数调用上下文的编码结果。API5的输出包括目标函数的函数调用链。也就是说,得到目标函数的函数调用链后,可以通过API5返回函数调用链。
API5的输入可以为四元组的形式,四元组中的线程入口函数指的是目标函数所属的线程的线程入口函数,encoding0指的是目标函数所属的线程的上下文的编码值,目标函数即为该函数调用链所调用的函数,encoding1指的是目标函数在所属线程内的函数调用上下文的编码值。
需要说明的是,本申请实施例中的API的输入中的函数可以通过函数名表示,或者也可以通过函数的内存地址表示,本申请实施例对函数的表示形式不做限定,只要能够指示相应的函数即可。API的输入中的编码值可以通过数值表示,或者也可以通过对应编码值的内存地址表示,本申请实施例对编码值的表示形式不做限定,只要能够指示相应的编码值即可。
(2)API6callstring=getdecoding(<X,目标函数,encoding1>)
API6用于获取函数调用链。API6的包括目标函数的调用上下文的编码结果。目标函数的调用上下文的编码结果包括目标函数所属的线程的上下文的编码结果和目标函数在所属线程内的函数调用上下文的编码结果。API6的输出包括目标函数的函数调用链。也就是说,得到目标函数的函数调用链后,可以通过API6返回该函数调用链。
API6的输入可以为三元组的形式,三元组中的X用于指示目标函数所属的线程的线程入口函数和目标函数所属的线程的上下文的编码值,目标函数即为该函数调用链所调用的函数,encoding1指的是目标函数在所属线程内的函数调用上下文的编码值。也就是说<X>可以理解对<线程入口函数,encoding0>的一种包装,X和线程入口函数,encoding0之间存在对应关系。
示例性地,X可以表示为字符串或者数字等形式,本申请实施例对X的表示形式不做限定,只要与<线程入口函数,encoding0>一一对应即可,即X能够唯一指示<线程入口函数,encoding0>即可。
根据本申请实施例中的解码方法,可以与本申请实施例中的编码方法适配使用,由目标函数的调用上下文的编码结果得到目标函数的函数调用链,能够灵活转换目标函数的调用上下文的编码结果和函数调用链,有利于应用于多种分析场景中,兼容其他分析方法。
下面结合图14至图17对本申请实施例的装置进行说明。应理解,下面描述的装置能够执行前述本申请实施例的方法,为了避免不必要的重复,下面在介绍本申请实施例的装置时适当省略重复的描述。
图14是本申请实施例的函数的调用上下文的编码装置的示意性框图。
示例性地,图14所示的装置1400可以位于图5静态程序分析器或图6的调用上下文编码模块630中。
图14所示的装置1400包括获取单元1410和处理单元1420。
获取单元1410和处理单元1420可以用于执行本申请实施例的函数的调用上下文的编码方法700。
获取单元单元1410,用于:获取目标函数的调用上下文信息;获取程序代码中的多个线程之间的创建关系对应的编码值,程序代码包括目标函数。
处理单元1420用于:根据目标函数的调用上下文信息和多个线程之间的创建关系对应的编码值对目标函数所属的线程的上下文进行编码,得到目标函数所属的线程的上下文的编码结果。
可选地,作为一个实施例,程序代码中的多个线程包括父线程和子线程,父线程中的线程创建函数用于创建子线程,父线程和子线程之间的创建关系对应的编码值与父线程中的线程创建函数的函数调用上下文对应。
可选地,作为一个实施例,目标函数所属的线程的上下文的编码结果用于指示目标函数所属的线程中的线程入口函数和目标函数所属的线程的上下文的编码值。
可选地,作为一个实施例,获取单元1410还用于:获取程序代码中的多个线程内的多个函数之间的调用关系对应的编码值;处理单元1420还用于:根据目标函数的调用上下文信息和程序代码中的多个线程内的多个函数之间的调用关系对应的编码值对目标函数在所属线程内的函数调用上下文进行编码,得到目标函数在所属线程内的函数调用上下文的编码结果。
可选地,作为一个实施例,多个线程中的一个线程内的多个函数之间的调用关系对应的编码值与多个函数之间的函数调用语句对应。
可选地,作为一个实施例,目标函数在所属线程内的函数调用上下文的编码结果用于指示目标函数和目标函数在所属线程内的函数调用上下文的编码值。
可选地,作为一个实施例,目标函数的调用上下文信息包括目标函数的函数调用链。
可选地,作为一个实施例,处理单元1420具体用于:在函数调用链中包括线程创建函数所创建的线程入口函数的情况下,以函数调用链中的线程创建函数为分割点,将函数调用链分为至少两个子链,至少两个子链中的每个子链中的起始点为线程入口函数;根据多个线程内的多个函数之间的调用关系对应的编码值分别确定至少两个子链中的多个函 数之间的调用关系对应的编码值;根据至少两个子链中的多个函数之间的调用关系对应的编码值分别确定至少两个子链中的线程创建函数在所属线程内的函数调用上下文对应的编码结果;根据至少两个子链中的线程创建函数在所属线程内的函数调用上下文对应的编码结果确定至少两个子链对应的线程之间的创建关系对应的编码值;将至少两个子链对应的线程之间的创建关系对应的编码值之和作为目标函数所属的线程的上下文的编码值;根据函数调用链中尾端的子链中的线程入口函数和目标函数所属的线程的上下文的编码值确定目标函数所属的线程的上下文的编码结果。
可选地,作为一个实施例,目标函数的调用上下文信息包括目标函数的调用者函数的调用上下文的编码结果和第一指令,目标函数为调用者函数通过第一指令调用的函数,调用者函数的调用上下文的编码结果包括调用者函数所属的线程的上下文的编码结果和调用者函数在所属线程内的函数调用上下文的编码结果。
可选地,作为一个实施例,处理单元1420具体用于:在第一指令为函数调用指令的情况下,将调用者函数所属的线程的上下文的编码结果作为目标函数所属的线程的上下文的编码结果;在第一指令为线程创建指令的情况下,根据调用者函数在所属线程内的函数调用上下文的编码结果确定调用者函数所属线程和目标函数所属线程之间的创建关系对应的编码值;将调用者函数所属的线程的上下文的编码值以及调用者函数所属线程和目标函数所属线程之间的创建关系对应的编码值之和作为目标函数所属的线程的上下文的编码值;根据目标函数和目标函数所属的线程的上下文的编码值确定目标函数所属的线程的上下文的编码结果。
可选地,作为一个实施例,目标函数的上下文信息包括被目标函数调用的被调函数的调用上下文的编码结果和第二指令,被调函数为目标函数通过第二指令调用的,被调函数的调用上下文的编码结果包括被调函数所属的线程的上下文的编码结果和被调函数在所属线程内的函数调用上下文的编码结果。
可选地,作为一个实施例,处理单元1420具体用于:在第二指令为函数调用指令的情况下,将被调函数所属的线程的上下文的编码结果作为目标函数所属的线程的上下文的编码结果;在第二指令为线程创建指令的情况下,根据被调函数所属的线程的上下文的编码结果确定目标函数所属线程和被调函数所属线程之间的创建关系对应的编码值;将被调函数所属的线程的上下文的编码值与目标函数所属线程和被调函数所属线程之间的创建关系对应的编码值之差作为目标函数所属的线程的上下文的编码值;根据目标函数所属线程的线程入口函数和目标函数所属的线程的上下文的编码值确定目标函数所属的线程的上下文的编码结果。
可选地,作为一个实施例,装置还包括API提供单元,用于提供API,API的输入包括目标函数的调用上下文信息,API的输出包括目标函数所属的线程的上下文的编码结果。
在一种实现方式中,API提供单元可以包括接收模块和输出模块,接收模块用于获取目标函数的调用上下文信息。在该情况下,装置1400可以通过该API获取目标函数的调用上下文信息,而不用通过获取单元获取目标函数的调用上下文信息。
可选地,作为一个实施例,API的输出还包括:目标函数在所属线程内的函数调用上下文的编码结果。
可选地,作为一个实施例,API的输出包括第一元素、第二元素、第三元素和第四元 素,第一元素用于指示目标函数所属的线程中的线程入口函数,第二元素用于指示目标函数所属的线程的上下文编码值,第三元素用于指示目标函数,第四元素用于指示目标函数在所属线程内的函数调用上下文的编码值。
可选地,作为一个实施例,API的输出包括第五元素、第六元素和第七元素,第五元素用于指示目标函数所属的线程中的线程入口函数和目标函数所属的线程的上下文编码值,第六元素用于指示目标函数,第七元素用于指示目标函数在所属线程内的函数调用上下文的编码值。图15是本申请实施例的函数的调用上下文的解码装置的示意性框图。图15所示的装置1500包括获取单元1510和处理单元1520。
示例性地,图15所示的装置1500可以位于图5静态程序分析器或图6的调用上下文解码模块640中。
获取单元1510和处理单元1520可以用于执行本申请实施例的函数的调用上下文的解码方法1700。
获取单元1510,用于:用于获取目标函数的调用上下文的编码结果;获取程序代码中的多个线程之间的创建关系对应的编码值,程序代码包括目标函数;获取程序代码中的多个线程内的多个函数之间的调用关系对应的编码值。
处理单元1520用于:根据程序代码中的多个线程之间的创建关系对应的编码值和程序代码中的多个线程内的多个函数之间的调用关系对应的编码值对目标函数的调用上下文的编码结果进行解码,得到目标函数的函数调用链。
可选地,作为一个实施例,程序代码中的多个线程包括父线程和子线程,父线程中的线程创建函数用于创建子线程,父线程和子线程之间的创建关系对应的编码值与父线程中的线程创建函数的函数调用上下文对应。
可选地,作为一个实施例,目标函数的调用上下文的编码结果包括目标函数所属的线程的上下文的编码结果和目标函数在所属线程内的函数调用上下文的编码结果,目标函数所属的线程的上下文的编码结果用于指示目标函数所属的线程中的线程入口函数和目标函数所属的线程的上下文的编码值;目标函数在所属线程内的函数调用上下文的编码结果用于指示目标函数和目标函数在所属线程内的函数调用上下文的编码值。
可选地,作为一个实施例,处理单元1520具体用于:根据程序代码中的多个线程之间的创建关系对应的编码值对目标函数所属的线程的上下文的编码结果进行解码,得到目标函数所属的线程的上下文中的多个线程之间的创建关系对应的编码值,其中,目标函数所属的线程的上下文中的多个线程之间的创建关系对应的编码值之和等于目标函数所属的线程的上下文的编码值,目标函数所属的线程是根据目标函数所属的线程中的线程入口函数确定的;根据目标函数所属的线程的上下文中的多个线程之间的创建关系对应的编码值确定目标函数所属的线程的上下文中的多个线程中的线程创建函数的函数调用上下文的编码结果;根据程序代码中的多个线程内的多个函数之间的调用关系对应的编码值对目标函数所属的线程的上下文中的多个线程中的线程创建函数的函数调用上下文的编码结果进行解码,得到线程创建函数在所属线程内的函数调用链,其中,线程创建函数在所属线程内的函数调用链的调用起点为线程创建函数所属的线程的线程入口函数,线程创建函数在所属线程内的函数调用链的调用终点为线程创建函数,线程创建函数在所属线程内的函数调用链中的多个函数之间的调用关系对应的编码值之和等于线程创建函数在所属线 程内的函数调用链的编码值;根据程序代码中的多个线程内的多个函数之间的调用关系对应的编码值对目标函数在所属线程内的函数调用上下文的编码结果进行解码,得到目标函数在所属线程内的函数调用链,其中,目标函数在所属线程内的函数调用链的调用起点为目标函数所属的线程的线程入口函数,目标函数在所属线程内的函数调用链的调用终点为目标函数,在目标函数在所属线程内的函数调用链的调用起点与目标函数在所属线程内的函数调用链的调用终点不同的情况下,目标函数在所属线程内的函数调用链中的多个函数之间的调用关系对应的编码值之和等于目标函数在所属线程内的函数调用上下文的编码值;根据线程创建函数在所属线程内的函数调用链和目标函数在所属线程内的函数调用链确定目标函数的函数调用链。
可选地,作为一个实施例,装置1500还包括API提供单元,用于提供API,API的输入包括目标函数的调用上下文的编码结果,API的输出包括目标函数的函数调用链。
可选地,作为一个实施例,API的输入包括第一元素、第二元素、第三元素和第四元素,第一元素用于指示目标函数所属的线程中的线程入口函数,第二元素用于指示目标函数所属的线程的上下文编码值,第三元素用于指示目标函数,第四元素用于指示目标函数在所属线程内的函数调用上下文的编码值。
可选地,作为一个实施例,API的输入包括第五元素、第六元素和第七元素,第五元素用于指示目标函数所属的线程中的线程入口函数和目标函数所属的线程的上下文编码值,第六元素用于指示目标函数,第七元素用于指示目标函数在所属线程内的函数调用上下文的编码值。
需要说明的是,上述装置1400和装置1500以功能单元的形式体现。这里的术语“单元”可以通过软件和/或硬件形式实现,对此不作具体限定。
例如,“单元”可以是实现上述功能的软件程序、硬件电路或二者结合。所述硬件电路可能包括应用特有集成电路(application specific integrated circuit,ASIC)、电子电路、用于执行一个或多个软件或固件程序的处理器(例如共享处理器、专有处理器或组处理器等)和存储器、合并逻辑电路和/或其它支持所描述的功能的合适组件。
因此,在本申请的实施例中描述的各示例的单元,能够以电子硬件、或者计算机软件和电子硬件的结合来实现。这些功能究竟以硬件还是软件方式来执行,取决于技术方案的特定应用和设计约束条件。专业技术人员可以对每个特定的应用来使用不同方法来实现所描述的功能,但是这种实现不应认为超出本申请的范围。
图16是本申请实施例提供的函数的调用上下文的编码装置的硬件结构示意图。图16所示的函数的调用上下文的编码装置1600(该装置1600具体可以是一种计算机设备)包括存储器1601、处理器1602、通信接口1603以及总线1604。其中,存储器1601、处理器1602、通信接口1603通过总线1604实现彼此之间的通信连接。
存储器1601可以是只读存储器(read only memory,ROM),静态存储设备,动态存储设备或者随机存取存储器(random access memory,RAM)。存储器1601可以存储程序,当存储器1601中存储的程序被处理器1602执行时,处理器1602和通信接口1603用于执行本申请实施例的函数的调用上下文的编码方法的各个步骤。
处理器1602可以采用通用的中央处理器(central processing unit,CPU),微处理器,应用专用集成电路(application specific Integrated circuit,ASIC),图形处理器(graphics processing unit,GPU)或者一个或多个集成电路,用于执行相关程序,以实现本申请实施例的。。装置中的单元所需执行的功能,或者执行本申请方法实施例的函数的调用上下文的编码方法。
处理器1602还可以是一种集成电路芯片,具有信号的处理能力。在实现过程中,本申请的函数的调用上下文的编码方法的各个步骤可以通过处理器1602中的硬件的集成逻辑电路或者软件形式的指令完成。上述的处理器1602还可以是通用处理器、数字信号处理器(digital signal processing,DSP)、专用集成电路(ASIC)、现成可编程门阵列(field programmable gate array,FPGA)或者其他可编程逻辑器件、分立门或者晶体管逻辑器件、分立硬件组件。可以实现或者执行本申请实施例中的公开的各方法、步骤及逻辑框图。通用处理器可以是微处理器或者该处理器也可以是任何常规的处理器等。结合本申请实施例所公开的方法的步骤可以直接体现为硬件译码处理器执行完成,或者用译码处理器中的硬件及软件模块组合执行完成。软件模块可以位于随机存储器,闪存、只读存储器,可编程只读存储器或者电可擦写可编程存储器、寄存器等本领域成熟的存储介质中。该存储介质位于存储器1601,处理器1602读取存储器1601中的信息,结合其硬件完成本申请实施例的函数的调用上下文的编码装置中包括的单元所需执行的功能,或者执行本申请方法实施例的函数的调用上下文的编码方法。
通信接口1603使用例如但不限于收发器一类的收发装置,来实现装置1600与其他设备或通信网络之间的通信。
总线1604可包括在装置1600各个部件(例如,存储器1601、处理器1602、通信接口1603)之间传送信息的通路。
应理解,函数的调用上下文的编码装置1400中的获取单元1410相当于函数的调用上下文的编码装置1600中的通信接口1603;函数的调用上下文的编码装置1400中的处理单元1420可以相当于处理器1602。
图17是本申请实施例提供的函数的调用上下文的解码装置的硬件结构示意图。图17所示的函数的调用上下文的解码装置1700(该装置1700具体可以是一种计算机设备)包括存储器1701、处理器1702、通信接口1703以及总线1704。其中,存储器1701、处理器1702、通信接口1703通过总线1704实现彼此之间的通信连接。
存储器1701可以是只读存储器(read only memory,ROM),静态存储设备,动态存储设备或者随机存取存储器(random access memory,RAM)。存储器1701可以存储程序,当存储器1701中存储的程序被处理器1702执行时,处理器1702和通信接口1703用于执行本申请实施例的函数的调用上下文的解码方法的各个步骤。
处理器1702可以采用通用的中央处理器(central processing unit,CPU),微处理器,应用专用集成电路(application specific Integrated circuit,ASIC),图形处理器(graphics processing unit,GPU)或者一个或多个集成电路,用于执行相关程序,以实现本申请实施例的函数的调用上下文的解码装置中的单元所需执行的功能,或者执行本申请方法实施例的函数的调用上下文的解码方法。
处理器1702还可以是一种集成电路芯片,具有信号的处理能力。在实现过程中,本申请的函数的调用上下文的解码方法的各个步骤可以通过处理器1702中的硬件的集成逻辑电路或者软件形式的指令完成。上述的处理器1702还可以是通用处理器、数字信号处 理器(digital signal processing,DSP)、专用集成电路(ASIC)、现成可编程门阵列(field programmable gate array,FPGA)或者其他可编程逻辑器件、分立门或者晶体管逻辑器件、分立硬件组件。可以实现或者执行本申请实施例中的公开的各方法、步骤及逻辑框图。通用处理器可以是微处理器或者该处理器也可以是任何常规的处理器等。结合本申请实施例所公开的方法的步骤可以直接体现为硬件译码处理器执行完成,或者用译码处理器中的硬件及软件模块组合执行完成。软件模块可以位于随机存储器,闪存、只读存储器,可编程只读存储器或者电可擦写可编程存储器、寄存器等本领域成熟的存储介质中。该存储介质位于存储器1701,处理器1702读取存储器1701中的信息,结合其硬件完成本申请实施例的函数的调用上下文的解码装置中包括的单元所需执行的功能,或者执行本申请方法实施例的函数的调用上下文的解码方法。
通信接口1703使用例如但不限于收发器一类的收发装置,来实现装置1700与其他设备或通信网络之间的通信。
总线1704可包括在装置1700各个部件(例如,存储器1701、处理器1702、通信接口1703)之间传送信息的通路。
应理解,函数的调用上下文的解码装置1500中的获取单元1510相当于函数的调用上下文的解码装置1700中的通信接口1703;函数的调用上下文的解码装置1500中的处理单元1520可以相当于处理器1702。
应注意,尽管图16、图17所示的装置仅仅示出了存储器、处理器、通信接口,但是在具体实现过程中,本领域的技术人员应当理解,装置1600、装置1700还包括实现正常运行所必须的其他器件。同时,根据具体需要,本领域的技术人员应当理解,装置1600、装置1700还可包括实现其他附加功能的硬件器件。此外,本领域的技术人员应当理解,装置1600、装置1700也可仅仅包括实现本申请实施例所必须的器件,而不必包括图16、图17中所示的全部器件。
所属领域的技术人员可以清楚地了解到,为描述的方便和简洁,上述描述的系统、装置和单元的具体工作过程,可以参考前述方法实施例中的对应过程,在此不再赘述。
应理解,本申请实施例中的处理器可以为中央处理单元(central processing unit,CPU),该处理器还可以是其他通用处理器、数字信号处理器(digital signal processor,DSP)、专用集成电路(application specific integrated circuit,ASIC)、现成可编程门阵列(field programmable gate array,FPGA)或者其他可编程逻辑器件、分立门或者晶体管逻辑器件、分立硬件组件等。通用处理器可以是微处理器或者该处理器也可以是任何常规的处理器等。
还应理解,本申请实施例中的存储器可以是易失性存储器或非易失性存储器,或可包括易失性和非易失性存储器两者。其中,非易失性存储器可以是只读存储器(read-only memory,ROM)、可编程只读存储器(programmable ROM,PROM)、可擦除可编程只读存储器(erasable PROM,EPROM)、电可擦除可编程只读存储器(electrically EPROM,EEPROM)或闪存。易失性存储器可以是随机存取存储器(random access memory,RAM),其用作外部高速缓存。通过示例性但不是限制性说明,许多形式的随机存取存储器(random access memory,RAM)可用,例如静态随机存取存储器(static RAM,SRAM)、动态随机存取存储器(DRAM)、同步动态随机存取存储器(synchronous DRAM,SDRAM)、双倍数据速率同步动态随机存取存储器(double data rate SDRAM,DDR SDRAM)、增强 型同步动态随机存取存储器(enhanced SDRAM,ESDRAM)、同步连接动态随机存取存储器(synchlink DRAM,SLDRAM)和直接内存总线随机存取存储器(direct rambus RAM,DR RAM)。
上述实施例,可以全部或部分地通过软件、硬件、固件或其他任意组合来实现。当使用软件实现时,上述实施例可以全部或部分地以计算机程序产品的形式实现。所述计算机程序产品包括一个或多个计算机指令或计算机程序。在计算机上加载或执行所述计算机指令或计算机程序时,全部或部分地产生按照本申请实施例所述的流程或功能。所述计算机可以为通用计算机、专用计算机、计算机网络、或者其他可编程装置。所述计算机指令可以存储在计算机可读存储介质中,或者从一个计算机可读存储介质向另一个计算机可读存储介质传输,例如,所述计算机指令可以从一个网站站点、计算机、服务器或数据中心通过有线(例如红外、无线、微波等)方式向另一个网站站点、计算机、服务器或数据中心进行传输。所述计算机可读存储介质可以是计算机能够存取的任何可用介质或者是包含一个或多个可用介质集合的服务器、数据中心等数据存储设备。所述可用介质可以是磁性介质(例如,软盘、硬盘、磁带)、光介质(例如,DVD)、或者半导体介质。半导体介质可以是固态硬盘。
应理解,本文中术语“和/或”,仅仅是一种描述关联对象的关联关系,表示可以存在三种关系,例如,A和/或B,可以表示:单独存在A,同时存在A和B,单独存在B这三种情况,其中A,B可以是单数或者复数。另外,本文中字符“/”,一般表示前后关联对象是一种“或”的关系,但也可能表示的是一种“和/或”的关系,具体可参考前后文进行理解。
本申请中,“至少一个”是指一个或者多个,“多个”是指两个或两个以上。“以下至少一项(个)”或其类似表达,是指的这些项中的任意组合,包括单项(个)或复数项(个)的任意组合。例如,a,b,或c中的至少一项(个),可以表示:a,b,c,a-b,a-c,b-c,或a-b-c,其中a,b,c可以是单个,也可以是多个。
应理解,在本申请的各种实施例中,上述各过程的序号的大小并不意味着执行顺序的先后,各过程的执行顺序应以其功能和内在逻辑确定,而不应对本申请实施例的实施过程构成任何限定。
本领域普通技术人员可以意识到,结合本文中所公开的实施例描述的各示例的单元及算法步骤,能够以电子硬件、或者计算机软件和电子硬件的结合来实现。这些功能究竟以硬件还是软件方式来执行,取决于技术方案的特定应用和设计约束条件。专业技术人员可以对每个特定的应用来使用不同方法来实现所描述的功能,但是这种实现不应认为超出本申请的范围。
所属领域的技术人员可以清楚地了解到,为描述的方便和简洁,上述描述的系统、装置和单元的具体工作过程,可以参考前述方法实施例中的对应过程,在此不再赘述。
在本申请所提供的几个实施例中,应该理解到,所揭露的系统、装置和方法,可以通过其它的方式实现。例如,以上所描述的装置实施例仅仅是示意性的,例如,所述单元的划分,仅仅为一种逻辑功能划分,实际实现时可以有另外的划分方式,例如多个单元或组件可以结合或者可以集成到另一个系统,或一些特征可以忽略,或不执行。另一点,所显示或讨论的相互之间的耦合或直接耦合或通信连接可以是通过一些接口,装置或单元的间 接耦合或通信连接,可以是电性,机械或其它的形式。
所述作为分离部件说明的单元可以是或者也可以不是物理上分开的,作为单元显示的部件可以是或者也可以不是物理单元,即可以位于一个地方,或者也可以分布到多个网络单元上。可以根据实际的需要选择其中的部分或者全部单元来实现本实施例方案的目的。
另外,在本申请各个实施例中的各功能单元可以集成在一个处理单元中,也可以是各个单元单独物理存在,也可以两个或两个以上单元集成在一个单元中。
所述功能如果以软件功能单元的形式实现并作为独立的产品销售或使用时,可以存储在一个计算机可读取存储介质中。基于这样的理解,本申请的技术方案本质上或者说对现有技术做出贡献的部分或者该技术方案的部分可以以软件产品的形式体现出来,该计算机软件产品存储在一个存储介质中,包括若干指令用以使得一台计算机设备(可以是个人计算机,服务器,或者网络设备等)执行本申请各个实施例所述方法的全部或部分步骤。而前述的存储介质包括:U盘、移动硬盘、只读存储器(Read-Only Memory,ROM)、随机存取存储器(Random Access Memory,RAM)、磁碟或者光盘等各种可以存储程序代码的介质。
以上所述,仅为本申请的具体实施方式,但本申请的保护范围并不局限于此,任何熟悉本技术领域的技术人员在本申请揭露的技术范围内,可轻易想到变化或替换,都应涵盖在本申请的保护范围之内。因此,本申请的保护范围应以所述权利要求的保护范围为准。

Claims (50)

  1. 一种函数的调用上下文的编码方法,其特征在于,包括:
    获取目标函数的调用上下文信息;
    获取程序代码中的多个线程之间的创建关系对应的编码值,所述程序代码包括所述目标函数;
    根据所述目标函数的调用上下文信息和所述多个线程之间的创建关系对应的编码值对所述目标函数所属的线程的上下文进行编码,得到所述目标函数所属的线程的上下文的编码结果。
  2. 根据权利要求2所述的方法,其特征在于,所述程序代码中的多个线程包括父线程和子线程,所述父线程中的线程创建函数用于创建所述子线程,所述父线程和所述子线程之间的创建关系对应的编码值与所述父线程中的线程创建函数的函数调用上下文对应。
  3. 根据权利要求1或2所述的方法,其特征在于,所述目标函数所属的线程的上下文的编码结果用于指示所述目标函数所属的线程中的线程入口函数和所述目标函数所属的线程的上下文的编码值。
  4. 根据权利要求1至3中任一项所述的方法,其特征在于,所述方法还包括:
    获取所述程序代码中的多个线程内的多个函数之间的调用关系对应的编码值;
    根据所述目标函数的调用上下文信息和所述程序代码中的多个线程内的多个函数之间的调用关系对应的编码值对所述目标函数在所属线程内的函数调用上下文进行编码,得到所述目标函数在所属线程内的函数调用上下文的编码结果。
  5. 根据权利要求4所述的方法,其特征在于,所述多个线程中的一个线程内的多个函数之间的调用关系对应的编码值与所述多个函数之间的函数调用语句对应。
  6. 根据权利要求4或5所述的方法,其特征在于,所述目标函数在所属线程内的函数调用上下文的编码结果用于指示所述目标函数和所述目标函数在所属线程内的函数调用上下文的编码值。
  7. 根据权利要求1至6中任一项所述的方法,其特征在于,所述目标函数的调用上下文信息包括所述目标函数的函数调用链。
  8. 根据权利要求7所述的方法,其特征在于,所述根据所述目标函数的调用上下文信息和所述多个线程之间的创建关系对应的编码值对所述目标函数所属的线程的上下文进行编码,得到所述目标函数所属的线程的上下文的编码结果,包括:
    在所述函数调用链中包括线程创建函数所创建的线程入口函数的情况下,以所述函数调用链中的线程创建函数为分割点,将所述函数调用链分为至少两个子链,所述至少两个子链中的每个子链中的起始点为线程入口函数;
    根据所述多个线程内的多个函数之间的调用关系对应的编码值分别确定所述至少两个子链中的多个函数之间的调用关系对应的编码值;
    根据所述至少两个子链中的多个函数之间的调用关系对应的编码值分别确定所述至少两个子链中的线程创建函数在所属线程内的函数调用上下文对应的编码结果;
    根据所述至少两个子链中的线程创建函数在所属线程内的函数调用上下文对应的编 码结果确定所述至少两个子链对应的线程之间的创建关系对应的编码值;
    将所述至少两个子链对应的线程之间的创建关系对应的编码值之和作为所述目标函数所属的线程的上下文的编码值;
    根据所述函数调用链中尾端的子链中的线程入口函数和所述目标函数所属的线程的上下文的编码值确定所述目标函数所属的线程的上下文的编码结果。
  9. 根据权利要求1至6中任一项所述的方法,其特征在于,所述目标函数的调用上下文信息包括所述目标函数的调用者函数的调用上下文的编码结果和第一指令,所述目标函数为所述调用者函数通过所述第一指令调用的函数,所述调用者函数的调用上下文的编码结果包括所述调用者函数所属的线程的上下文的编码结果和所述调用者函数在所属线程内的函数调用上下文的编码结果。
  10. 根据权利要求9所述的方法,其特征在于,所述根据所述目标函数的调用上下文信息和所述多个线程之间的创建关系对应的编码值对所述目标函数所属的线程的上下文进行编码,得到所述目标函数所属的线程的上下文的编码结果,包括:
    在所述第一指令为函数调用指令的情况下,将所述调用者函数所属的线程的上下文的编码结果作为所述目标函数所属的线程的上下文的编码结果;
    在所述第一指令为线程创建指令的情况下,根据所述调用者函数在所属线程内的函数调用上下文的编码结果确定所述调用者函数所属线程和所述目标函数所属线程之间的创建关系对应的编码值;将所述调用者函数所属的线程的上下文的编码值以及所述调用者函数所属线程和所述目标函数所属线程之间的创建关系对应的编码值之和作为所述目标函数所属的线程的上下文的编码值;根据所述目标函数和所述目标函数所属的线程的上下文的编码值确定所述目标函数所属的线程的上下文的编码结果。
  11. 根据权利要求1至6中任一项所述的方法,其特征在于,所述目标函数的上下文信息包括被所述目标函数调用的被调函数的调用上下文的编码结果和第二指令,所述被调函数为所述目标函数通过所述第二指令调用的,所述被调函数的调用上下文的编码结果包括所述被调函数所属的线程的上下文的编码结果和所述被调函数在所属线程内的函数调用上下文的编码结果。
  12. 根据权利要求11所述的方法,其特征在于,所述根据所述目标函数的调用上下文信息和所述多个线程之间的创建关系对应的编码值对所述目标函数所属的线程的上下文进行编码,得到所述目标函数所属的线程的上下文的编码结果,包括:
    在所述第二指令为函数调用指令的情况下,将所述被调函数所属的线程的上下文的编码结果作为所述目标函数所属的线程的上下文的编码结果;
    在所述第二指令为线程创建指令的情况下,根据所述被调函数所属的线程的上下文的编码结果确定所述目标函数所属线程和所述被调函数所属线程之间的创建关系对应的编码值;将所述被调函数所属的线程的上下文的编码值与所述目标函数所属线程和所述被调函数所属线程之间的创建关系对应的编码值之差作为所述目标函数所属的线程的上下文的编码值;根据所述目标函数所属线程的线程入口函数和所述目标函数所属的线程的上下文的编码值确定所述目标函数所属的线程的上下文的编码结果。
  13. 根据权利要求1至12中任一项所述的方法,其特征在于,所述方法还包括:
    提供API,所述API的输入包括所述目标函数的调用上下文信息,所述API的输出包 括所述目标函数所属的线程的上下文的编码结果。
  14. 根据权利要求13所述的方法,其特征在于,所述API的输出还包括:所述目标函数在所属线程内的函数调用上下文的编码结果。
  15. 根据权利要求14所述的方法,其特征在于,所述API的输出包括第一元素、第二元素、第三元素和第四元素,所述第一元素用于指示所述目标函数所属的线程中的线程入口函数,所述第二元素用于指示所述目标函数所属的线程的上下文编码值,所述第三元素用于指示所述目标函数,所述第四元素用于指示所述目标函数在所属线程内的函数调用上下文的编码值。
  16. 根据权利要求14所述的方法,其特征在于,所述API的输出包括第五元素、第六元素和第七元素,所述第五元素用于指示所述目标函数所属的线程中的线程入口函数和所述目标函数所属的线程的上下文编码值,所述第六元素用于指示所述目标函数,所述第七元素用于指示所述目标函数在所属线程内的函数调用上下文的编码值。
  17. 一种函数的调用上下文的解码方法,其特征在于,包括:
    获取目标函数的调用上下文的编码结果;
    获取程序代码中的多个线程之间的创建关系对应的编码值,所述程序代码包括所述目标函数;
    获取所述程序代码中的多个线程内的多个函数之间的调用关系对应的编码值;
    根据所述程序代码中的多个线程之间的创建关系对应的编码值和所述程序代码中的多个线程内的多个函数之间的调用关系对应的编码值对所述目标函数的调用上下文的编码结果进行解码,得到所述目标函数的函数调用链。
  18. 根据权利要求17所述的方法,其特征在于,所述程序代码中的多个线程包括父线程和子线程,所述父线程中的线程创建函数用于创建所述子线程,所述父线程和所述子线程之间的创建关系对应的编码值与所述父线程中的线程创建函数的函数调用上下文对应。
  19. 根据权利要求17或18所述的方法,其特征在于,所述目标函数的调用上下文的编码结果包括所述目标函数所属的线程的上下文的编码结果和所述目标函数在所属线程内的函数调用上下文的编码结果,所述目标函数所属的线程的上下文的编码结果用于指示所述目标函数所属的线程中的线程入口函数和所述目标函数所属的线程的上下文的编码值;所述目标函数在所属线程内的函数调用上下文的编码结果用于指示所述目标函数和所述目标函数在所属线程内的函数调用上下文的编码值。
  20. 根据权利要求19所述的方法,其特征在于,所述根据所述程序代码中的多个线程之间的创建关系对应的编码值和所述程序代码中的多个线程内的多个函数之间的调用关系对应的编码值对所述目标函数的调用上下文的编码结果进行解码,得到目标函数的函数调用链,包括:
    根据所述程序代码中的多个线程之间的创建关系对应的编码值对所述目标函数所属的线程的上下文的编码结果进行解码,得到所述目标函数所属的线程的上下文中的多个线程之间的创建关系对应的编码值,其中,所述目标函数所属的线程的上下文中的多个线程之间的创建关系对应的编码值之和等于所述目标函数所属的线程的上下文的编码值,所述目标函数所属的线程是根据所述目标函数所属的线程中的线程入口函数确定的;
    根据所述目标函数所属的线程的上下文中的多个线程之间的创建关系对应的编码值确定所述目标函数所属的线程的上下文中的多个线程中的线程创建函数的函数调用上下文的编码结果;
    根据所述程序代码中的多个线程内的多个函数之间的调用关系对应的编码值对所述目标函数所属的线程的上下文中的多个线程中的线程创建函数的函数调用上下文的编码结果进行解码,得到所述线程创建函数在所属线程内的函数调用链,其中,所述线程创建函数在所属线程内的函数调用链的调用起点为所述线程创建函数所属的线程的线程入口函数,所述线程创建函数在所属线程内的函数调用链的调用终点为所述线程创建函数,所述线程创建函数在所属线程内的函数调用链中的多个函数之间的调用关系对应的编码值之和等于所述线程创建函数在所属线程内的函数调用链的编码值;
    根据所述程序代码中的多个线程内的多个函数之间的调用关系对应的编码值对所述目标函数在所属线程内的函数调用上下文的编码结果进行解码,得到所述目标函数在所属线程内的函数调用链,其中,所述目标函数在所属线程内的函数调用链的调用起点为所述目标函数所属的线程的线程入口函数,所述目标函数在所属线程内的函数调用链的调用终点为所述目标函数,在所述目标函数在所属线程内的函数调用链的调用起点与所述目标函数在所属线程内的函数调用链的调用终点不同的情况下,所述目标函数在所属线程内的函数调用链中的多个函数之间的调用关系对应的编码值之和等于所述目标函数在所属线程内的函数调用上下文的编码值;
    根据所述线程创建函数在所属线程内的函数调用链和所述目标函数在所属线程内的函数调用链确定所述目标函数的函数调用链。
  21. 根据权利要求17至20中任一项所述的方法,其特征在于,所述方法还包括:
    提供API,所述API的输入包括所述目标函数的调用上下文的编码结果,所述API的输出包括所述目标函数的函数调用链。
  22. 根据权利要求21所述的方法,其特征在于,所述API的输入包括第一元素、第二元素、第三元素和第四元素,所述第一元素用于指示所述目标函数所属的线程中的线程入口函数,所述第二元素用于指示所述目标函数所属的线程的上下文编码值,所述第三元素用于指示所述目标函数,所述第四元素用于指示所述目标函数在所属线程内的函数调用上下文的编码值。
  23. 根据权利要求21所述的方法,其特征在于,所述API的输入包括第五元素、第六元素和第七元素,所述第五元素用于指示所述目标函数所属的线程中的线程入口函数和所述目标函数所属的线程的上下文编码值,所述第六元素用于指示所述目标函数,所述第七元素用于指示所述目标函数在所属线程内的函数调用上下文的编码值。
  24. 一种函数的调用上下文的编码装置,其特征在于,所述装置包括:
    获取单元,用于:
    获取目标函数的调用上下文信息;
    获取程序代码中的多个线程之间的创建关系对应的编码值,所述程序代码包括所述目标函数;
    处理单元,用于:
    根据所述目标函数的调用上下文信息和所述多个线程之间的创建关系对应的编码值 对所述目标函数所属的线程的上下文进行编码,得到所述目标函数所属的线程的上下文的编码结果。
  25. 根据权利要求24所述的装置,其特征在于,所述程序代码中的多个线程包括父线程和子线程,所述父线程中的线程创建函数用于创建所述子线程,所述父线程和所述子线程之间的创建关系对应的编码值与所述父线程中的线程创建函数的函数调用上下文对应。
  26. 根据权利要求24或25所述的装置,其特征在于,所述目标函数所属的线程的上下文的编码结果用于指示所述目标函数所属的线程中的线程入口函数和所述目标函数所属的线程的上下文的编码值。
  27. 根据根据权利要求24至26中任一项所述的装置,其特征在于,所述获取单元还用于:获取所述程序代码中的多个线程内的多个函数之间的调用关系对应的编码值;
    所述处理单元还用于:根据所述目标函数的调用上下文信息和所述程序代码中的多个线程内的多个函数之间的调用关系对应的编码值对所述目标函数在所属线程内的函数调用上下文进行编码,得到所述目标函数在所属线程内的函数调用上下文的编码结果。
  28. 根据权利要求27所述的装置,其特征在于,所述多个线程中的一个线程内的多个函数之间的调用关系对应的编码值与所述多个函数之间的函数调用语句对应。
  29. 根据权利要求27或28所述的装置,其特征在于,所述目标函数在所属线程内的函数调用上下文的编码结果用于指示所述目标函数和所述目标函数在所属线程内的函数调用上下文的编码值。
  30. 根据权利要求24至29中任一项所述的装置,其特征在于,所述目标函数的调用上下文信息包括所述目标函数的函数调用链。
  31. 根据权利要求30所述的装置,其特征在于,所述处理单元具体用于:
    在所述函数调用链中包括线程创建函数所创建的线程入口函数的情况下,以所述函数调用链中的线程创建函数为分割点,将所述函数调用链分为至少两个子链,所述至少两个子链中的每个子链中的起始点为线程入口函数;
    根据所述多个线程内的多个函数之间的调用关系对应的编码值分别确定所述至少两个子链中的多个函数之间的调用关系对应的编码值;
    根据所述至少两个子链中的多个函数之间的调用关系对应的编码值分别确定所述至少两个子链中的线程创建函数在所属线程内的函数调用上下文对应的编码结果;
    根据所述至少两个子链中的线程创建函数在所属线程内的函数调用上下文对应的编码结果确定所述至少两个子链对应的线程之间的创建关系对应的编码值;
    将所述至少两个子链对应的线程之间的创建关系对应的编码值之和作为所述目标函数所属的线程的上下文的编码值;
    根据所述函数调用链中尾端的子链中的线程入口函数和所述目标函数所属的线程的上下文的编码值确定所述目标函数所属的线程的上下文的编码结果。
  32. 根据权利要求24至29中任一项所述的装置,其特征在于,所述目标函数的调用上下文信息包括所述目标函数的调用者函数的调用上下文的编码结果和第一指令,所述目标函数为所述调用者函数通过所述第一指令调用的函数,所述调用者函数的调用上下文的编码结果包括所述调用者函数所属的线程的上下文的编码结果和所述调用者函数在所属 线程内的函数调用上下文的编码结果。
  33. 根据权利要求32所述的装置,其特征在于,所述处理单元具体用于:
    在所述第一指令为函数调用指令的情况下,将所述调用者函数所属的线程的上下文的编码结果作为所述目标函数所属的线程的上下文的编码结果;
    在所述第一指令为线程创建指令的情况下,根据所述调用者函数在所属线程内的函数调用上下文的编码结果确定所述调用者函数所属线程和所述目标函数所属线程之间的创建关系对应的编码值;将所述调用者函数所属的线程的上下文的编码值以及所述调用者函数所属线程和所述目标函数所属线程之间的创建关系对应的编码值之和作为所述目标函数所属的线程的上下文的编码值;根据所述目标函数和所述目标函数所属的线程的上下文的编码值确定所述目标函数所属的线程的上下文的编码结果。
  34. 根据权利要求24至29中任一项所述的装置,其特征在于,所述目标函数的上下文信息包括被所述目标函数调用的被调函数的调用上下文的编码结果和第二指令,所述被调函数为所述目标函数通过所述第二指令调用的,所述被调函数的调用上下文的编码结果包括所述被调函数所属的线程的上下文的编码结果和所述被调函数在所属线程内的函数调用上下文的编码结果。
  35. 根据权利要求34所述的装置,其特征在于,所述处理单元具体用于:
    在所述第二指令为函数调用指令的情况下,将所述被调函数所属的线程的上下文的编码结果作为所述目标函数所属的线程的上下文的编码结果;
    在所述第二指令为线程创建指令的情况下,根据所述被调函数所属的线程的上下文的编码结果确定所述目标函数所属线程和所述被调函数所属线程之间的创建关系对应的编码值;将所述被调函数所属的线程的上下文的编码值与所述目标函数所属线程和所述被调函数所属线程之间的创建关系对应的编码值之差作为所述目标函数所属的线程的上下文的编码值;根据所述目标函数所属线程的线程入口函数和所述目标函数所属的线程的上下文的编码值确定所述目标函数所属的线程的上下文的编码结果。
  36. 根据权利要求24至35中任一项所述的装置,其特征在于,所述装置还包括API提供单元,用于提供API,所述API的输入包括所述目标函数的调用上下文信息,所述API的输出包括所述目标函数所属的线程的上下文的编码结果。
  37. 根据权利要求36所述的装置,其特征在于,所述API的输出还包括:所述目标函数在所属线程内的函数调用上下文的编码结果。
  38. 根据权利要求37所述的装置,其特征在于,所述API的输出包括第一元素、第二元素、第三元素和第四元素,所述第一元素用于指示所述目标函数所属的线程中的线程入口函数,所述第二元素用于指示所述目标函数所属的线程的上下文编码值,所述第三元素用于指示所述目标函数,所述第四元素用于指示所述目标函数在所属线程内的函数调用上下文的编码值。
  39. 根据权利要求37所述的装置,其特征在于,所述API的输出包括第五元素、第六元素和第七元素,所述第五元素用于指示所述目标函数所属的线程中的线程入口函数和所述目标函数所属的线程的上下文编码值,所述第六元素用于指示所述目标函数,所述第七元素用于指示所述目标函数在所属线程内的函数调用上下文的编码值。
  40. 一种函数的调用上下文的解码装置,其特征在于,所述装置包括:
    获取单元,用于获取目标函数的调用上下文的编码结果;
    获取程序代码中的多个线程之间的创建关系对应的编码值,所述程序代码包括所述目标函数;
    获取所述程序代码中的多个线程内的多个函数之间的调用关系对应的编码值;
    处理单元,用于:
    根据所述程序代码中的多个线程之间的创建关系对应的编码值和所述程序代码中的多个线程内的多个函数之间的调用关系对应的编码值对所述目标函数的调用上下文的编码结果进行解码,得到所述目标函数的函数调用链。
  41. 根据权利要求40所述的装置,其特征在于,所述程序代码中的多个线程包括父线程和子线程,所述父线程中的线程创建函数用于创建所述子线程,所述父线程和所述子线程之间的创建关系对应的编码值与所述父线程中的线程创建函数的函数调用上下文对应。
  42. 根据权利要求40或41所述的装置,其特征在于,所述目标函数的调用上下文的编码结果包括所述目标函数所属的线程的上下文的编码结果和所述目标函数在所属线程内的函数调用上下文的编码结果,所述目标函数所属的线程的上下文的编码结果用于指示所述目标函数所属的线程中的线程入口函数和所述目标函数所属的线程的上下文的编码值;所述目标函数在所属线程内的函数调用上下文的编码结果用于指示所述目标函数和所述目标函数在所属线程内的函数调用上下文的编码值。
  43. 根据权利要求42所述的装置,其特征在于,所述处理单元具体用于:
    根据所述程序代码中的多个线程之间的创建关系对应的编码值对所述目标函数所属的线程的上下文的编码结果进行解码,得到所述目标函数所属的线程的上下文中的多个线程之间的创建关系对应的编码值,其中,所述目标函数所属的线程的上下文中的多个线程之间的创建关系对应的编码值之和等于所述目标函数所属的线程的上下文的编码值,所述目标函数所属的线程是根据所述目标函数所属的线程中的线程入口函数确定的;
    根据所述目标函数所属的线程的上下文中的多个线程之间的创建关系对应的编码值确定所述目标函数所属的线程的上下文中的多个线程中的线程创建函数的函数调用上下文的编码结果;
    根据所述程序代码中的多个线程内的多个函数之间的调用关系对应的编码值对所述目标函数所属的线程的上下文中的多个线程中的线程创建函数的函数调用上下文的编码结果进行解码,得到所述线程创建函数在所属线程内的函数调用链,其中,所述第线程创建函数在所属线程内的函数调用链的调用起点为所述线程创建函数所属的线程的线程入口函数,所述线程创建函数在所属线程内的函数调用链的调用终点为所述线程创建函数,所述线程创建函数在所属线程内的函数调用链中的多个函数之间的调用关系对应的编码值之和等于所述线程创建函数在所属线程内的函数调用链的编码值;
    根据所述程序代码中的多个线程内的多个函数之间的调用关系对应的编码值对所述目标函数在所属线程内的函数调用上下文的编码结果进行解码,得到所述目标函数在所属线程内的函数调用链,其中,所述目标函数在所属线程内的函数调用链的调用起点为所述目标函数所属的线程的线程入口函数,所述目标函数在所属线程内的函数调用链的调用终点为所述目标函数,在所述目标函数在所属线程内的函数调用链的调用起点与所述目标函 数在所属线程内的函数调用链的调用终点不同的情况下,所述目标函数在所属线程内的函数调用链中的多个函数之间的调用关系对应的编码值之和等于所述目标函数在所属线程内的函数调用上下文的编码值;
    根据所述线程创建函数在所属线程内的函数调用链和所述目标函数在所属线程内的函数调用链确定所述目标函数的函数调用链。
  44. 根据权利要求40至43中任一项所述的装置,其特征在于,所述装置还包括API提供单元,用于提供API,所述API的输入包括所述目标函数的调用上下文的编码结果,所述API的输出包括所述目标函数的函数调用链。
  45. 根据权利要求44所述的装置,其特征在于,所述API的输入包括第一元素、第二元素、第三元素和第四元素,所述第一元素用于指示所述目标函数所属的线程中的线程入口函数,所述第二元素用于指示所述目标函数所属的线程的上下文编码值,所述第三元素用于指示所述目标函数,所述第四元素用于指示所述目标函数在所属线程内的函数调用上下文的编码值。
  46. 根据权利要求44所述的装置,其特征在于,所述API的输入包括第五元素、第六元素和第七元素,所述第五元素用于指示所述目标函数所属的线程中的线程入口函数和所述目标函数所属的线程的上下文编码值,所述第六元素用于指示所述目标函数,所述第七元素用于指示所述目标函数在所属线程内的函数调用上下文的编码值。
  47. 一种函数的调用上下文的编码装置,其特征在于,包括处理器和存储器,所述存储器用于存储程序指令,所述处理器用于调用所述程序指令来执行权利要求1至16中任一项所述的方法。
  48. 一种函数的调用上下文的解码装置,其特征在于,包括处理器和存储器,所述存储器用于存储程序指令,所述处理器用于调用所述程序指令来执行权利要求17至23中任一项所述的方法。
  49. 一种计算机可读存储介质,其特征在于,所述计算机可读介质存储用于设备执行的程序代码,该程序代码包括用于执行如权利要求1至16或17至23中任一项所述的方法。
  50. 一种芯片,其特征在于,所述芯片包括处理器与数据接口,所述处理器通过所述数据接口读取存储器上存储的指令,以执行如权利要求1至16或12至23中任一项所述的方法。
CN202180088006.7A 2021-02-27 2021-02-27 函数调用上下文的编码、解码方法及装置 Pending CN116710894A (zh)

Applications Claiming Priority (1)

Application Number Priority Date Filing Date Title
PCT/CN2021/078327 WO2022178889A1 (zh) 2021-02-27 2021-02-27 函数调用上下文的编码、解码方法及装置

Publications (1)

Publication Number Publication Date
CN116710894A true CN116710894A (zh) 2023-09-05

Family

ID=83047700

Family Applications (1)

Application Number Title Priority Date Filing Date
CN202180088006.7A Pending CN116710894A (zh) 2021-02-27 2021-02-27 函数调用上下文的编码、解码方法及装置

Country Status (4)

Country Link
US (1) US20230409373A1 (zh)
EP (1) EP4290372A4 (zh)
CN (1) CN116710894A (zh)
WO (1) WO2022178889A1 (zh)

Family Cites Families (9)

* Cited by examiner, † Cited by third party
Publication number Priority date Publication date Assignee Title
US6263491B1 (en) * 1998-10-02 2001-07-17 Microsoft Corporation Heavyweight and lightweight instrumentation
CN102693133B (zh) * 2012-05-22 2016-04-06 东南大学 一种带环路径的编码、执行及解码方法
US9367428B2 (en) * 2013-10-14 2016-06-14 Nec Corporation Transparent performance inference of whole software layers and context-sensitive performance debugging
CN105224305B (zh) * 2014-07-01 2018-09-28 华为技术有限公司 函数调用路径编解码方法、装置及系统
CN104199649B (zh) * 2014-08-22 2017-04-05 东南大学 一种用于父子进程间交互信息的路径剖析方法
US10496433B2 (en) * 2014-11-24 2019-12-03 Red Hat, Inc. Modification of context saving functions
CN106257425B (zh) * 2016-07-20 2019-04-09 东南大学 一种基于并发控制流图的Java并发程序路径剖析方法
CN109783222A (zh) * 2017-11-15 2019-05-21 杭州华为数字技术有限公司 一种消除分支分歧的方法及设备
CN110266669B (zh) * 2019-06-06 2021-08-17 武汉大学 一种Java Web框架漏洞攻击通用检测与定位的方法及系统

Also Published As

Publication number Publication date
US20230409373A1 (en) 2023-12-21
EP4290372A4 (en) 2024-04-10
WO2022178889A1 (zh) 2022-09-01
EP4290372A1 (en) 2023-12-13

Similar Documents

Publication Publication Date Title
US20090037386A1 (en) Computer file processing
WO2013070561A1 (en) External serialization and deserialization
CN110825385A (zh) React Native离线包的构建方法及存储介质
US8141082B2 (en) Node-based representation of multi-threaded computing environment tasks, and node-based data race evaluation
US8667507B2 (en) Deep copying objects in a collocated environment
US11157249B1 (en) Method and system for identifying and extracting independent services from a computer program
CN111913878B (zh) 基于程序分析结果的字节码插桩方法、装置及存储介质
CN113296786A (zh) 数据处理方法、装置、电子设备及存储介质
CN110609703B (zh) 性能检测工具实现方法、装置、可读存储介质及终端设备
EP2972880B1 (en) Kernel functionality checker
US8607204B2 (en) Method of analyzing single thread access of variable in multi-threaded program
CN109582300A (zh) 基于路径的代码变更分析方法、装置及设备
CN116710894A (zh) 函数调用上下文的编码、解码方法及装置
CN116880847A (zh) 基于开源项目的溯源方法、装置电子设备及存储介质
CN103577170A (zh) 网络应用的构建方法及装置
CN114443455A (zh) 死循环检测方法及装置
CN112612471B (zh) 代码处理方法、装置、设备及存储介质
Runwal et al. Code clone detection based on logical similarity: A review
CN117251171B (zh) 一种控制流图中谓词基本块检测方法及设备
CN114091111B (zh) 一种区块链智能合约的存储方法及装置
CN113031959B (zh) 变量替换方法、装置、系统及存储介质
CN114780952B (zh) 敏感应用调用场景的检测方法、系统及存储介质
WO2023093761A1 (zh) 处理数据的方法和相关装置
Kožul et al. Framework and Database Handler Implementation for an Automotive Test Environment Generator
CN115016795A (zh) 代码相似度的检测方法及装置、处理器和电子设备

Legal Events

Date Code Title Description
PB01 Publication
PB01 Publication
SE01 Entry into force of request for substantive examination
SE01 Entry into force of request for substantive examination