21 from Load.loadData
import loadLib
22 from Tool.tool
import removeParameter,getFileName,resolvePythonExecutable,buildRunCommand,getArtifactHash,getArtifactDisplayName
23 from Extract.getCall
import getCallFunction
24 from Preprocess.preprocess
import addDictSingle
35 capilst=callApi.split(
'.')
39 if capilst[-1]==keylst[-1]:
40 candidate[k]=len(set(capilst)&set(keylst))/len(keylst)
42 ansKey=sorted(candidate,key=
lambda i:candidate[i],reverse=
True)[0]
43 realName=assignDict[ansKey]
58 libAPIs,assignDict,libAPIIns=
loadLib(libName,version)
60 if builtinFlag
and len(libAPIIns)>0:
61 ans=Fuzz.fmatch(formatAPI,libAPIIns)
63 ans=Fuzz.fmatch(formatAPI,libAPIs)
65 if len(ans)==0
and not builtinFlag:
67 realName=
isAlias(aliasName,assignDict)
68 if realName
is not None:
69 ans=Fuzz.fmatch(realName,libAPIs)
79 return {apiName:[parameters]}
81 if apiName
not in ansDict:
83 ansDict[apiName].append(parameters)
98 if not isinstance(dynamicMatchDict,dict):
100 dataDir=runtimePaths[
'data_dir']
101 phase=
'current' if curr
else 'target'
104 safeVersion=str(version).replace(os.sep,
'_').replace(
'/',
'_').replace(
'\\',
'_')
105 snapshotDict=dict(dynamicMatchDict)
107 snapshotDict[
'_pcart']={
109 'version': str(version),
115 if pklFile
is not None:
116 snapshotDict[
'_pcart'][
'pklFile']=pklFile
117 os.makedirs(dataDir,exist_ok=
True)
118 fileName=f
"{phase}_{safeKey}_{safeVersion}_dynamicMatch.json"
119 with open(os.path.join(dataDir,fileName),
'w',encoding=
'UTF-8')
as fw:
120 json.dump(snapshotDict,fw,indent=4,ensure_ascii=
False)
130 copyRoot=runtimePaths[
'copy_root']
131 manifestPath=os.path.join(copyRoot,
'pkl',
getFileName(pklKey,
'.manifest.json'))
132 if not os.path.exists(manifestPath):
135 with open(manifestPath,
'r',encoding=
'UTF-8')
as fr:
136 manifest=json.load(fr)
139 if not manifest.get(
'covered'):
141 for candidate
in manifest.get(
'candidates',[]):
142 if candidate.get(
'status')==
'save_failed':
164 def dynamicMatch(callAPI,runCommand,runPath,projName,copyFile,version,virtualEnv,lock,errLst,curr=1,*,callKey,runtimePaths):
167 copyRoot=runtimePaths[
'copy_root']
168 dynamicRoot=runtimePaths[
'dynamic_root']
169 dataDir=runtimePaths[
'data_dir']
173 pklCandidateFiles=[pklFile[:-4]+
'__object.pkl',pklFile[:-4]+
'__expr.pkl',pklFile]
177 if runPath
and runPath
not in runCommand:
178 dynamic_cwd = os.path.join(dynamicRoot, projName, runPath)
179 dynamic_script =
'dynamicMatch.py'
181 dynamic_cwd = os.path.join(dynamicRoot, projName)
182 dynamic_script = os.path.join(runPath,
'dynamicMatch.py')
if runPath
else 'dynamicMatch.py'
184 lastDynamicMatchDict =
None
185 existingPklFiles=[file
for file
in pklCandidateFiles
if os.path.exists(os.path.join(copyRoot,
'pkl',file))]
186 if not existingPklFiles:
189 lastResult=subprocess.CompletedProcess([],1,
'',
'manifest save_failed')
191 for candidatePklFile
in existingPklFiles:
193 pkl_arg = os.path.join(copyRoot,
'pkl', candidatePklFile)
194 matchResult = subprocess.run(
195 [pythonPath, dynamic_script, pkl_arg, callAPI, dataDir, pklKey],
196 cwd=dynamic_cwd, capture_output=
True, text=
True, encoding=
'utf-8'
198 lastResult = matchResult
199 if matchResult.returncode == 0:
201 matchJsonPath=os.path.join(dataDir,fileName)
202 with open(matchJsonPath,
'r',encoding=
'UTF-8')
as fr:
204 dynamicMatchDict=json.load(fr)
205 except Exception
as e:
206 dynamicMatchDict=
None
207 print(f
"json load {matchJsonPath} failed: {e}\n")
208 lastDynamicMatchDict = dynamicMatchDict
209 if dynamicMatchDict
and dynamicMatchDict.get(
'match') !=
'nullptr':
211 return dynamicMatchDict
215 if lastResult
is None:
218 stdout = lastResult.stdout
219 stderr = lastResult.stderr
220 matchResult = lastResult
222 if matchResult.returncode!=0:
224 errLst.append(f
"{callAPI}, Failed to load pkl in current version{version}: {matchResult.stderr}\n")
230 elif stderr
and 'Ran out of input' not in stderr:
231 loadError=f
"{callAPI}, Failed to load pkl in target version{version}: {matchResult.stderr}\n"
233 shutil.copy2(copyFile,f
"{copyFile}.bak")
235 regeneratedPklFiles=[]
236 if runPath
and runPath
not in runCommand:
237 copy_cwd = os.path.join(copyRoot, projName, runPath)
239 copy_cwd = os.path.join(copyRoot, projName)
242 generateResult = subprocess.run(
243 cmd, cwd=copy_cwd, capture_output=
True, text=
True, encoding=
'utf-8'
245 if generateResult.returncode==0:
247 regeneratedCandidates=[
248 (
'paraValue__object.pkl',
'new_'+pklFile[:-4]+
'__object.pkl'),
249 (
'paraValue__expr.pkl',
'new_'+pklFile[:-4]+
'__expr.pkl'),
250 (
'paraValue.pkl',
'new_'+pklFile),
252 for sourceName,targetName
in regeneratedCandidates:
253 sourcePath=os.path.join(copyRoot,
'pkl',sourceName)
254 if os.path.exists(sourcePath):
255 targetPath=os.path.join(copyRoot,
'pkl',targetName)
256 os.replace(sourcePath,targetPath)
257 regeneratedPklFiles.append(targetName)
261 shutil.move(f
'{copyFile}.bak',copyFile)
263 if generateResult.returncode!=0:
264 errLst.append(loadError)
265 errLst.append(f
'[{version}]{callAPI}, generate new pkl failed: {generateResult.stderr}\n')
268 if not regeneratedPklFiles:
269 errLst.append(f
'[{version}]{callAPI}, generate new pkl failed: no pkl file generated\n')
271 for regeneratedPklFile
in regeneratedPklFiles:
272 pkl_arg = os.path.join(copyRoot,
'pkl', regeneratedPklFile)
273 matchResult = subprocess.run(
274 [pythonPath, dynamic_script, pkl_arg, callAPI, dataDir, pklKey],
275 cwd=dynamic_cwd, capture_output=
True, text=
True, encoding=
'utf-8'
277 if matchResult.returncode!=0:
280 matchJsonPath=os.path.join(dataDir,fileName)
281 with open(matchJsonPath,
'r',encoding=
'UTF-8')
as fr:
283 dynamicMatchDict=json.load(fr)
284 except Exception
as e:
285 dynamicMatchDict=
None
286 print(f
"json load {matchJsonPath} failed: {e}\n")
287 if dynamicMatchDict
and dynamicMatchDict.get(
'match') !=
'nullptr':
289 return dynamicMatchDict
290 lastDynamicMatchDict=dynamicMatchDict
291 if lastDynamicMatchDict:
293 return lastDynamicMatchDict
294 errLst.append(f
"[{version}]{callAPI}, load new pkl failed: {matchResult.stderr}\n")
301 if lastDynamicMatchDict:
303 return lastDynamicMatchDict
328 def mapAPI(callAPI,runCommand,runPath,formatAPI,projName,libName,copyFile,version,virtualEnv,lock,errLst,curr=1,*,callKey,runtimePaths):
329 dynamicMatchDict=
dynamicMatch(callAPI,runCommand,runPath,projName,copyFile,version,virtualEnv,lock,errLst,curr,callKey=callKey,runtimePaths=runtimePaths)
331 ans[
'format']=formatAPI
332 if dynamicMatchDict!=
False:
333 result=dynamicMatchDict[
'match']
334 ans[
'error']=dynamicMatchDict[
'error']
335 if 'internalPath' in dynamicMatchDict:
336 ans[
'internalPath']=dynamicMatchDict[
'internalPath']
338 ans[
'internalPath']=formatAPI
340 if 'builtin' in dynamicMatchDict[
'error']:
341 ans[
'match']=
fuzzymatch(formatAPI,libName,version,1)
342 ans[
'matchMethod']=
'static'
343 elif result==
'nullptr':
344 ans[
'match']=
fuzzymatch(formatAPI,libName,version,0)
345 ans[
'matchMethod']=
'static'
348 ans[
'matchMethod']=
'dynamic'
350 ans[
'match']=
fuzzymatch(formatAPI,libName,version,0)
351 ans[
'matchMethod']=
'static'
Provide class definitions for statically mapping API parameter definitions.
def loadLib(libName, version)
Load the extracted definitions of lib APIs for static signature mapping 把之前抽取出来的库API加载到字典中,在项目API与库AP...
def hasSaveFailedManifest(pklKey, *runtimePaths)
Check whether a callsite candidate manifest records pkl save failure 检查调用点候选清单是否记录了pkl保存失败
def saveDynamicMatchSnapshot(pklKey, version, curr, dynamicMatchDict, pklFile=None, *runtimePaths)
Save dynamic match result snapshot 保存动态匹配结果快照
def mapAPI(callAPI, runCommand, runPath, formatAPI, projName, libName, copyFile, version, virtualEnv, lock, errLst, curr=1, *callKey, runtimePaths)
Construct the mapping between the invoked API and the lib API to obtain its signature 建立invoked API与 ...
def isAlias(callApi, assignDict)
Check whether the last name in an API call is an alias 判断一个callAPI最后一个名字是否为库中的别名
def fuzzymatch(formatAPI, libName, version, builtinFlag)
Static mapping of API signatures API签名静态匹配
def dynamicMatch(callAPI, runCommand, runPath, projName, copyFile, version, virtualEnv, lock, errLst, curr=1, *callKey, runtimePaths)
Dynamic mapping of API signatures API签名动态匹配
def addDictSingle(callAPI, filePath, callKey)
Code instrumentation for a single API call within a source file 源文件单个API调用代码插桩