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([pythonPath, dynamic_script, pkl_arg, callAPI, dataDir, pklKey],cwd=dynamic_cwd, capture_output=
True, text=
True, encoding=
'utf-8')
195 lastResult = matchResult
196 if matchResult.returncode == 0:
198 matchJsonPath=os.path.join(dataDir,fileName)
199 with open(matchJsonPath,
'r',encoding=
'UTF-8')
as fr:
201 dynamicMatchDict=json.load(fr)
202 except Exception
as e:
203 dynamicMatchDict=
None
204 print(f
"json load {matchJsonPath} failed: {e}\n")
205 lastDynamicMatchDict = dynamicMatchDict
206 if dynamicMatchDict
and dynamicMatchDict.get(
'match') !=
'nullptr':
208 return dynamicMatchDict
212 if lastResult
is None:
215 stdout = lastResult.stdout
216 stderr = lastResult.stderr
217 matchResult = lastResult
219 if matchResult.returncode!=0:
221 errLst.append(f
"{callAPI}, Failed to load pkl in current version{version}: {matchResult.stderr}\n")
227 elif stderr
and 'Ran out of input' not in stderr:
228 loadError=f
"{callAPI}, Failed to load pkl in target version{version}: {matchResult.stderr}\n"
230 shutil.copy2(copyFile,f
"{copyFile}.bak")
232 regeneratedPklFiles=[]
233 if runPath
and runPath
not in runCommand:
234 copy_cwd = os.path.join(copyRoot, projName, runPath)
236 copy_cwd = os.path.join(copyRoot, projName)
239 generateResult = subprocess.run(cmd, cwd=copy_cwd, capture_output=
True, text=
True, encoding=
'utf-8')
240 if generateResult.returncode==0:
242 regeneratedCandidates=[
243 (
'paraValue__object.pkl',
'new_'+pklFile[:-4]+
'__object.pkl'),
244 (
'paraValue__expr.pkl',
'new_'+pklFile[:-4]+
'__expr.pkl'),
245 (
'paraValue.pkl',
'new_'+pklFile),
247 for sourceName,targetName
in regeneratedCandidates:
248 sourcePath=os.path.join(copyRoot,
'pkl',sourceName)
249 if os.path.exists(sourcePath):
250 targetPath=os.path.join(copyRoot,
'pkl',targetName)
251 os.replace(sourcePath,targetPath)
252 regeneratedPklFiles.append(targetName)
256 shutil.move(f
'{copyFile}.bak',copyFile)
258 if generateResult.returncode!=0:
259 errLst.append(loadError)
260 errLst.append(f
'[{version}]{callAPI}, generate new pkl failed: {generateResult.stderr}\n')
263 if not regeneratedPklFiles:
264 errLst.append(f
'[{version}]{callAPI}, generate new pkl failed: no pkl file generated\n')
266 for regeneratedPklFile
in regeneratedPklFiles:
267 pkl_arg = os.path.join(copyRoot,
'pkl', regeneratedPklFile)
268 matchResult = subprocess.run([pythonPath, dynamic_script, pkl_arg, callAPI, dataDir, pklKey],cwd=dynamic_cwd, capture_output=
True, text=
True, encoding=
'utf-8')
269 if matchResult.returncode!=0:
272 matchJsonPath=os.path.join(dataDir,fileName)
273 with open(matchJsonPath,
'r',encoding=
'UTF-8')
as fr:
275 dynamicMatchDict=json.load(fr)
276 except Exception
as e:
277 dynamicMatchDict=
None
278 print(f
"json load {matchJsonPath} failed: {e}\n")
279 if dynamicMatchDict
and dynamicMatchDict.get(
'match') !=
'nullptr':
281 return dynamicMatchDict
282 lastDynamicMatchDict=dynamicMatchDict
283 if lastDynamicMatchDict:
285 return lastDynamicMatchDict
286 errLst.append(f
"[{version}]{callAPI}, load new pkl failed: {matchResult.stderr}\n")
293 if lastDynamicMatchDict:
295 return lastDynamicMatchDict
320 def mapAPI(callAPI,runCommand,runPath,formatAPI,projName,libName,copyFile,version,virtualEnv,lock,errLst,curr=1,*,callKey,runtimePaths):
321 dynamicMatchDict=
dynamicMatch(callAPI,runCommand,runPath,projName,copyFile,version,virtualEnv,lock,errLst,curr,callKey=callKey,runtimePaths=runtimePaths)
323 ans[
'format']=formatAPI
324 if dynamicMatchDict!=
False:
325 result=dynamicMatchDict[
'match']
326 ans[
'error']=dynamicMatchDict[
'error']
327 if 'internalPath' in dynamicMatchDict:
328 ans[
'internalPath']=dynamicMatchDict[
'internalPath']
330 ans[
'internalPath']=formatAPI
331 if 'qualifiedName' in dynamicMatchDict:
332 ans[
'qualifiedName']=dynamicMatchDict[
'qualifiedName']
334 if 'builtin' in dynamicMatchDict[
'error']:
335 ans[
'match']=
fuzzymatch(formatAPI,libName,version,1)
336 ans[
'matchMethod']=
'static'
337 elif result==
'nullptr':
338 ans[
'match']=
fuzzymatch(formatAPI,libName,version,0)
339 ans[
'matchMethod']=
'static'
342 ans[
'matchMethod']=
'dynamic'
344 ans[
'match']=
fuzzymatch(formatAPI,libName,version,0)
345 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调用代码插桩