"""pep384_macrocheck.pyThis programm tries to locate errors in the relevant Python headerfiles where macros access type fields when they are reachable fromthe limided API.The idea is to search macros with the string "->tp_" in it.When the macro name does not begin with an underscore,then we have found a dormant error.Christian Tismer2018年06月02日"""import sysimport osimport reDEBUG = Falsedef dprint(*args, **kw):if DEBUG:print(*args, **kw)def parse_headerfiles(startpath):"""Scan all header files which are reachable fronm Python.h"""search = "Python.h"name = os.path.join(startpath, search)if not os.path.exists(name):raise ValueError("file {} was not found in {}\n""Please give the path to Python's include directory.".format(search, startpath))errors = 0with open(name) as python_h:while True:line = python_h.readline()if not line:breakfound = re.match(r'^\s*#\s*include\s*"(\w+\.h)"', line)if not found:continueinclude = found.group(1)dprint("Scanning", include)name = os.path.join(startpath, include)if not os.path.exists(name):name = os.path.join(startpath, "../PC", include)errors += parse_file(name)return errorsdef ifdef_level_gen():"""Scan lines for #ifdef and track the level."""level = 0ifdef_pattern = r"^\s*#\s*if" # covers ifdef and ifndef as wellendif_pattern = r"^\s*#\s*endif"while True:line = yield levelif re.match(ifdef_pattern, line):level += 1elif re.match(endif_pattern, line):level -= 1def limited_gen():"""Scan lines for Py_LIMITED_API yes(1) no(-1) or nothing (0)"""limited = [0] # nothingunlimited_pattern = r"^\s*#\s*ifndef\s+Py_LIMITED_API"limited_pattern = "|".join([r"^\s*#\s*ifdef\s+Py_LIMITED_API",r"^\s*#\s*(el)?if\s+!\s*defined\s*\(\s*Py_LIMITED_API\s*\)\s*\|\|",r"^\s*#\s*(el)?if\s+defined\s*\(\s*Py_LIMITED_API"])else_pattern = r"^\s*#\s*else"ifdef_level = ifdef_level_gen()status = next(ifdef_level)wait_for = -1while True:line = yield limited[-1]new_status = ifdef_level.send(line)dir = new_status - statusstatus = new_statusif dir == 1:if re.match(unlimited_pattern, line):limited.append(-1)wait_for = status - 1elif re.match(limited_pattern, line):limited.append(1)wait_for = status - 1elif dir == -1:# this must have been an endifif status == wait_for:limited.pop()wait_for = -1else:# it could be that we have an elifif re.match(limited_pattern, line):limited.append(1)wait_for = status - 1elif re.match(else_pattern, line):limited.append(-limited.pop()) # negate topdef parse_file(fname):errors = 0with open(fname) as f:lines = f.readlines()type_pattern = r"^.*?->\s*tp_"define_pattern = r"^\s*#\s*define\s+(\w+)"limited = limited_gen()status = next(limited)for nr, line in enumerate(lines):status = limited.send(line)line = line.rstrip()dprint(fname, nr, status, line)if status != -1:if re.match(define_pattern, line):name = re.match(define_pattern, line).group(1)if not name.startswith("_"):# found a candidate, check it!macro = line + "\n"idx = nrwhile line.endswith("\\"):idx += 1line = lines[idx].rstrip()macro += line + "\n"if re.match(type_pattern, macro, re.DOTALL):# this type field can reach the limited APIreport(fname, nr + 1, macro)errors += 1return errorsdef report(fname, nr, macro):f = sys.stderrprint(fname + ":" + str(nr), file=f)print(macro, file=f)if __name__ == "__main__":p = sys.argv[1] if sys.argv[1:] else "../../Include"errors = parse_headerfiles(p)if errors:# somehow it makes sense to raise a TypeError :-)raise TypeError("These {} locations contradict the limited API.".format(errors))
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。