diff options
author | Eric Snow <ericsnowcurrently@gmail.com> | 2023-03-14 16:05:54 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-03-14 16:05:54 (GMT) |
commit | 1ff81c0cb67215694f084e51c4d35ae53b9f5cf9 (patch) | |
tree | e8067aff7f52f7b17284caa3452b17a98a9ae1bc /Tools/c-analyzer/c_parser | |
parent | a703f743dbf2675948e59c44fa9d7112f7825100 (diff) | |
download | cpython-1ff81c0cb67215694f084e51c4d35ae53b9f5cf9.zip cpython-1ff81c0cb67215694f084e51c4d35ae53b9f5cf9.tar.gz cpython-1ff81c0cb67215694f084e51c4d35ae53b9f5cf9.tar.bz2 |
gh-81057: Add a CI Check for New Unsupported C Global Variables (gh-102506)
This will keep us from adding new unsupported (i.e. non-const) C global variables, which would break interpreter isolation.
FYI, historically it is very uncommon for new global variables to get added. Furthermore, it is rare for new code to break the c-analyzer. So the check should almost always pass unnoticed.
Note that I've removed test_check_c_globals. A test wasn't a great fit conceptually and was super slow on debug builds. A CI check is a better fit.
This also resolves gh-100237.
https://github.com/python/cpython/issues/81057
Diffstat (limited to 'Tools/c-analyzer/c_parser')
-rw-r--r-- | Tools/c-analyzer/c_parser/preprocessor/common.py | 6 | ||||
-rw-r--r-- | Tools/c-analyzer/c_parser/preprocessor/gcc.py | 23 |
2 files changed, 19 insertions, 10 deletions
diff --git a/Tools/c-analyzer/c_parser/preprocessor/common.py b/Tools/c-analyzer/c_parser/preprocessor/common.py index 4291a06..dbe1ede 100644 --- a/Tools/c-analyzer/c_parser/preprocessor/common.py +++ b/Tools/c-analyzer/c_parser/preprocessor/common.py @@ -115,15 +115,15 @@ def converted_error(tool, argv, filename): def convert_error(tool, argv, filename, stderr, rc): error = (stderr.splitlines()[0], rc) if (_expected := is_os_mismatch(filename, stderr)): - logger.debug(stderr.strip()) + logger.info(stderr.strip()) raise OSMismatchError(filename, _expected, argv, error, tool) elif (_missing := is_missing_dep(stderr)): - logger.debug(stderr.strip()) + logger.info(stderr.strip()) raise MissingDependenciesError(filename, (_missing,), argv, error, tool) elif '#error' in stderr: # XXX Ignore incompatible files. error = (stderr.splitlines()[1], rc) - logger.debug(stderr.strip()) + logger.info(stderr.strip()) raise ErrorDirectiveError(filename, argv, error, tool) else: # Try one more time, with stderr written to the terminal. diff --git a/Tools/c-analyzer/c_parser/preprocessor/gcc.py b/Tools/c-analyzer/c_parser/preprocessor/gcc.py index 7ef1a8a..24c1b0e 100644 --- a/Tools/c-analyzer/c_parser/preprocessor/gcc.py +++ b/Tools/c-analyzer/c_parser/preprocessor/gcc.py @@ -6,6 +6,11 @@ from . import common as _common TOOL = 'gcc' +META_FILES = { + '<built-in>', + '<command-line>', +} + # https://gcc.gnu.org/onlinedocs/cpp/Preprocessor-Output.html # flags: # 1 start of a new file @@ -75,11 +80,15 @@ def _iter_lines(text, reqfile, samefiles, cwd, raw=False): # The first line is special. # The next two lines are consistent. - for expected in [ - f'# 1 "{reqfile}"', - '# 1 "<built-in>"', - '# 1 "<command-line>"', - ]: + firstlines = [ + f'# 0 "{reqfile}"', + '# 0 "<built-in>"', + '# 0 "<command-line>"', + ] + if text.startswith('# 1 '): + # Some preprocessors emit a lineno of 1 for line-less entries. + firstlines = [l.replace('# 0 ', '# 1 ') for l in firstlines] + for expected in firstlines: line = next(lines) if line != expected: raise NotImplementedError((line, expected)) @@ -121,7 +130,7 @@ def _iter_top_include_lines(lines, topfile, cwd, # _parse_marker_line() that the preprocessor reported lno as 1. lno = 1 for line in lines: - if line == '# 1 "<command-line>" 2': + if line == '# 0 "<command-line>" 2' or line == '# 1 "<command-line>" 2': # We're done with this top-level include. return @@ -174,8 +183,8 @@ def _parse_marker_line(line, reqfile=None): return None, None, None lno, origfile, flags = m.groups() lno = int(lno) + assert origfile not in META_FILES, (line,) assert lno > 0, (line, lno) - assert origfile not in ('<built-in>', '<command-line>'), (line,) flags = set(int(f) for f in flags.split()) if flags else () if 1 in flags: |