cppcheck-py 2.20.0__py3-none-win32.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cppcheck/__init__.py +55 -0
- cppcheck/cppcheck-2.20.0.tar.gz +0 -0
- cppcheck/data/addons/__init__.py +0 -0
- cppcheck/data/addons/cppcheck.py +41 -0
- cppcheck/data/addons/cppcheckdata.py +1727 -0
- cppcheck/data/addons/findcasts.py +32 -0
- cppcheck/data/addons/misc.py +163 -0
- cppcheck/data/addons/misra.py +5153 -0
- cppcheck/data/addons/misra_9.py +559 -0
- cppcheck/data/addons/naming.py +92 -0
- cppcheck/data/addons/namingng.py +420 -0
- cppcheck/data/addons/runaddon.py +16 -0
- cppcheck/data/addons/threadsafety.py +350 -0
- cppcheck/data/addons/y2038.py +602 -0
- cppcheck/data/cfg/avr.cfg +402 -0
- cppcheck/data/cfg/bento4.cfg +142 -0
- cppcheck/data/cfg/boost.cfg +1284 -0
- cppcheck/data/cfg/bsd.cfg +567 -0
- cppcheck/data/cfg/cairo.cfg +90 -0
- cppcheck/data/cfg/cppcheck-lib.cfg +72 -0
- cppcheck/data/cfg/cppunit.cfg +48 -0
- cppcheck/data/cfg/dpdk.cfg +11 -0
- cppcheck/data/cfg/embedded_sql.cfg +4 -0
- cppcheck/data/cfg/emscripten.cfg +108 -0
- cppcheck/data/cfg/ginac.cfg +12848 -0
- cppcheck/data/cfg/gnu.cfg +1738 -0
- cppcheck/data/cfg/googletest.cfg +62 -0
- cppcheck/data/cfg/gtk.cfg +23086 -0
- cppcheck/data/cfg/icu.cfg +221 -0
- cppcheck/data/cfg/kde.cfg +92 -0
- cppcheck/data/cfg/libcerror.cfg +203 -0
- cppcheck/data/cfg/libcurl.cfg +487 -0
- cppcheck/data/cfg/libsigc++.cfg +36 -0
- cppcheck/data/cfg/lua.cfg +316 -0
- cppcheck/data/cfg/mfc.cfg +271 -0
- cppcheck/data/cfg/microsoft_atl.cfg +40 -0
- cppcheck/data/cfg/microsoft_sal.cfg +490 -0
- cppcheck/data/cfg/microsoft_unittest.cfg +20 -0
- cppcheck/data/cfg/motif.cfg +318 -0
- cppcheck/data/cfg/nspr.cfg +38 -0
- cppcheck/data/cfg/ntl.cfg +6907 -0
- cppcheck/data/cfg/opencv2.cfg +132 -0
- cppcheck/data/cfg/opengl.cfg +581 -0
- cppcheck/data/cfg/openmp.cfg +157 -0
- cppcheck/data/cfg/openssl.cfg +174 -0
- cppcheck/data/cfg/pcre.cfg +165 -0
- cppcheck/data/cfg/posix.cfg +6445 -0
- cppcheck/data/cfg/protobuf.cfg +10 -0
- cppcheck/data/cfg/python.cfg +674 -0
- cppcheck/data/cfg/qt.cfg +5502 -0
- cppcheck/data/cfg/ruby.cfg +142 -0
- cppcheck/data/cfg/sdl.cfg +354 -0
- cppcheck/data/cfg/selinux.cfg +3621 -0
- cppcheck/data/cfg/sfml.cfg +301 -0
- cppcheck/data/cfg/sqlite3.cfg +1571 -0
- cppcheck/data/cfg/std.cfg +9215 -0
- cppcheck/data/cfg/tinyxml2.cfg +37 -0
- cppcheck/data/cfg/vcl.cfg +4 -0
- cppcheck/data/cfg/windows.cfg +17237 -0
- cppcheck/data/cfg/wxsqlite3.cfg +1955 -0
- cppcheck/data/cfg/wxsvg.cfg +16905 -0
- cppcheck/data/cfg/wxwidgets.cfg +17313 -0
- cppcheck/data/cfg/zephyr.cfg +113 -0
- cppcheck/data/cfg/zlib.cfg +1450 -0
- cppcheck/data/cppcheck-htmlreport +1157 -0
- cppcheck/data/cppcheck.exe +0 -0
- cppcheck/data/platforms/aix_ppc64.xml +18 -0
- cppcheck/data/platforms/arm32-wchar_t2.xml +18 -0
- cppcheck/data/platforms/arm32-wchar_t4.xml +18 -0
- cppcheck/data/platforms/arm64-wchar_t2.xml +18 -0
- cppcheck/data/platforms/arm64-wchar_t4.xml +18 -0
- cppcheck/data/platforms/avr8.xml +18 -0
- cppcheck/data/platforms/cray_sv1.xml +18 -0
- cppcheck/data/platforms/elbrus-e1cp.xml +18 -0
- cppcheck/data/platforms/mips32.xml +18 -0
- cppcheck/data/platforms/msp430_eabi_large_datamodel.xml +18 -0
- cppcheck/data/platforms/pic16.xml +18 -0
- cppcheck/data/platforms/pic8-enhanced.xml +18 -0
- cppcheck/data/platforms/pic8.xml +18 -0
- cppcheck_py-2.20.0.dist-info/METADATA +76 -0
- cppcheck_py-2.20.0.dist-info/RECORD +84 -0
- cppcheck_py-2.20.0.dist-info/WHEEL +5 -0
- cppcheck_py-2.20.0.dist-info/entry_points.txt +4 -0
- cppcheck_py-2.20.0.dist-info/licenses/LICENSE.md +191 -0
|
@@ -0,0 +1,602 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
#
|
|
3
|
+
# cppcheck addon for Y2038 safeness detection
|
|
4
|
+
#
|
|
5
|
+
# This addon provides comprehensive Y2038 (Year 2038 Problem) detection for C/C++ code.
|
|
6
|
+
# It extracts compiler flags from cppcheck dump file configuration to determine
|
|
7
|
+
# Y2038 safety, suppressing warnings when proper configuration is detected.
|
|
8
|
+
#
|
|
9
|
+
# Key Features:
|
|
10
|
+
# - Extraction of Y2038-related flags from cppcheck dump file configuration
|
|
11
|
+
# - Compiler flag parsing and validation from cppcheck's project parsing
|
|
12
|
+
# - Warning suppression when proper Y2038 configuration is found
|
|
13
|
+
# - Support for both _TIME_BITS=64 and _FILE_OFFSET_BITS=64 requirements
|
|
14
|
+
# - Priority-based flag resolution (dump file configuration > source code directives)
|
|
15
|
+
#
|
|
16
|
+
# Detects:
|
|
17
|
+
#
|
|
18
|
+
# 1. _TIME_BITS being defined to something else than 64 bits
|
|
19
|
+
# 2. _FILE_OFFSET_BITS being defined to something else than 64 bits
|
|
20
|
+
# 3. _USE_TIME_BITS64 being defined when _TIME_BITS is not
|
|
21
|
+
# 4. Any Y2038-unsafe symbol when proper Y2038 configuration is not present
|
|
22
|
+
# 5. Dump file configurations that affect Y2038 safety
|
|
23
|
+
#
|
|
24
|
+
# Warning Suppression:
|
|
25
|
+
# When both _TIME_BITS=64 AND _FILE_OFFSET_BITS=64 are detected (prioritizing dump file
|
|
26
|
+
# configuration over source code directives), Y2038 warnings are suppressed and an
|
|
27
|
+
# informational message is displayed instead.
|
|
28
|
+
#
|
|
29
|
+
# Example usage:
|
|
30
|
+
# $ cppcheck --addon=y2038 path-to-src/test.c
|
|
31
|
+
# $ cppcheck --dump file.c && python3 y2038.py file.c.dump
|
|
32
|
+
#
|
|
33
|
+
|
|
34
|
+
from __future__ import print_function
|
|
35
|
+
|
|
36
|
+
import cppcheckdata
|
|
37
|
+
import sys
|
|
38
|
+
import re
|
|
39
|
+
|
|
40
|
+
# Y2038 flags are extracted by cppcheck core during project parsing
|
|
41
|
+
# and passed through dump file configuration - no redundant parsing needed
|
|
42
|
+
|
|
43
|
+
# --------------------------------
|
|
44
|
+
# Y2038 safety constants
|
|
45
|
+
# --------------------------------
|
|
46
|
+
|
|
47
|
+
# Y2038-safe bit values
|
|
48
|
+
Y2038_SAFE_TIME_BITS = 64
|
|
49
|
+
Y2038_SAFE_FILE_OFFSET_BITS = 64
|
|
50
|
+
|
|
51
|
+
# --------------------------------------------
|
|
52
|
+
# #define/#undef detection regular expressions
|
|
53
|
+
# --------------------------------------------
|
|
54
|
+
|
|
55
|
+
# test for '#define _TIME_BITS 64'
|
|
56
|
+
re_define_time_bits_64 = re.compile(rf'^\s*#\s*define\s+_TIME_BITS\s+{Y2038_SAFE_TIME_BITS}\s*$')
|
|
57
|
+
|
|
58
|
+
# test for '#define _TIME_BITS ...' (combine w/ above to test for 'not 64')
|
|
59
|
+
re_define_time_bits = re.compile(r'^\s*#\s*define\s+_TIME_BITS\s+.*$')
|
|
60
|
+
|
|
61
|
+
# test for '#undef _TIME_BITS' (if it ever happens)
|
|
62
|
+
re_undef_time_bits = re.compile(r'^\s*#\s*undef\s+_TIME_BITS\s*$')
|
|
63
|
+
|
|
64
|
+
# test for '#define _USE_TIME_BITS64'
|
|
65
|
+
re_define_use_time_bits64 = re.compile(r'^\s*#\s*define\s+_USE_TIME_BITS64\s*$')
|
|
66
|
+
|
|
67
|
+
# test for '#undef _USE_TIME_BITS64' (if it ever happens)
|
|
68
|
+
re_undef_use_time_bits64 = re.compile(r'^\s*#\s*undef\s+_USE_TIME_BITS64\s*$')
|
|
69
|
+
|
|
70
|
+
# test for '#define _FILE_OFFSET_BITS 64'
|
|
71
|
+
re_define_file_offset_bits_64 = re.compile(rf'^\s*#\s*define\s+_FILE_OFFSET_BITS\s+{Y2038_SAFE_FILE_OFFSET_BITS}\s*$')
|
|
72
|
+
|
|
73
|
+
# test for '#define _FILE_OFFSET_BITS ...' (combine w/ above to test for 'not 64')
|
|
74
|
+
re_define_file_offset_bits = re.compile(r'^\s*#\s*define\s+_FILE_OFFSET_BITS\s+.*$')
|
|
75
|
+
|
|
76
|
+
# test for '#undef _FILE_OFFSET_BITS' (if it ever happens)
|
|
77
|
+
re_undef_file_offset_bits = re.compile(r'^\s*#\s*undef\s+_FILE_OFFSET_BITS\s*$')
|
|
78
|
+
|
|
79
|
+
# --------------------------------------------
|
|
80
|
+
# Compiler flag parsing regular expressions
|
|
81
|
+
# --------------------------------------------
|
|
82
|
+
|
|
83
|
+
# test for '_TIME_BITS=64' in compiler flags
|
|
84
|
+
re_flag_time_bits_64 = re.compile(rf'_TIME_BITS={Y2038_SAFE_TIME_BITS}(?:\s|$|;)')
|
|
85
|
+
|
|
86
|
+
# test for '_TIME_BITS=...' in compiler flags (combine w/ above to test for 'not 64')
|
|
87
|
+
re_flag_time_bits = re.compile(r'_TIME_BITS=(\d+)')
|
|
88
|
+
|
|
89
|
+
# test for '_USE_TIME_BITS64' in compiler flags
|
|
90
|
+
re_flag_use_time_bits64 = re.compile(r'_USE_TIME_BITS64(?:\s|$|=|;)')
|
|
91
|
+
|
|
92
|
+
# test for '_FILE_OFFSET_BITS=64' in compiler flags
|
|
93
|
+
re_flag_file_offset_bits_64 = re.compile(rf'_FILE_OFFSET_BITS={Y2038_SAFE_FILE_OFFSET_BITS}(?:\s|$|;)')
|
|
94
|
+
|
|
95
|
+
# test for '_FILE_OFFSET_BITS=...' in compiler flags
|
|
96
|
+
re_flag_file_offset_bits = re.compile(r'_FILE_OFFSET_BITS=(\d+)')
|
|
97
|
+
|
|
98
|
+
# --------------------------------
|
|
99
|
+
# List of Y2038-unsafe identifiers
|
|
100
|
+
# --------------------------------
|
|
101
|
+
|
|
102
|
+
# This is WIP. Eventually it should contain all identifiers (types
|
|
103
|
+
# and functions) which would be affected by the Y2038 bug.
|
|
104
|
+
|
|
105
|
+
id_Y2038 = {
|
|
106
|
+
# Y2038-unsafe types by definition
|
|
107
|
+
'time_t'
|
|
108
|
+
# Types using Y2038-unsafe types
|
|
109
|
+
'lastlog',
|
|
110
|
+
'msqid_ds',
|
|
111
|
+
'semid_ds',
|
|
112
|
+
'timeb',
|
|
113
|
+
'timespec',
|
|
114
|
+
'timeval',
|
|
115
|
+
'utimbuf',
|
|
116
|
+
'itimerspec',
|
|
117
|
+
'clnt_ops',
|
|
118
|
+
'elf_prstatus',
|
|
119
|
+
'itimerval',
|
|
120
|
+
'ntptimeval',
|
|
121
|
+
'rusage',
|
|
122
|
+
'timex',
|
|
123
|
+
'utmp',
|
|
124
|
+
'utmpx',
|
|
125
|
+
# APIs using 2038-unsafe types
|
|
126
|
+
'ctime',
|
|
127
|
+
'ctime_r',
|
|
128
|
+
'difftime',
|
|
129
|
+
'gmtime',
|
|
130
|
+
'gmtime_r',
|
|
131
|
+
'localtime',
|
|
132
|
+
'localtime_r',
|
|
133
|
+
'mktime',
|
|
134
|
+
'stime',
|
|
135
|
+
'timegm',
|
|
136
|
+
'timelocal',
|
|
137
|
+
'time',
|
|
138
|
+
'msgctl',
|
|
139
|
+
'ftime',
|
|
140
|
+
'aio_suspend',
|
|
141
|
+
'clock_getres',
|
|
142
|
+
'clock_gettime',
|
|
143
|
+
'clock_nanosleep',
|
|
144
|
+
'clock_settime',
|
|
145
|
+
'futimens',
|
|
146
|
+
'mq_timedreceive',
|
|
147
|
+
'mq_timedsend',
|
|
148
|
+
'nanosleep',
|
|
149
|
+
'pselect',
|
|
150
|
+
'pthread_cond_timedwait',
|
|
151
|
+
'pthread_mutex_timedlock',
|
|
152
|
+
'pthread_rwlock_timedrdlock',
|
|
153
|
+
'pthread_rwlock_timedwrlock',
|
|
154
|
+
'sched_rr_get_interval',
|
|
155
|
+
'sem_timedwait',
|
|
156
|
+
'sigtimedwait',
|
|
157
|
+
'timespec_get',
|
|
158
|
+
'utimensat',
|
|
159
|
+
'adjtime',
|
|
160
|
+
'pmap_rmtcall',
|
|
161
|
+
'clntudp_bufcreate',
|
|
162
|
+
'clntudp_create',
|
|
163
|
+
'futimes',
|
|
164
|
+
'gettimeofday',
|
|
165
|
+
'lutimes',
|
|
166
|
+
'select',
|
|
167
|
+
'settimeofday',
|
|
168
|
+
'utimes',
|
|
169
|
+
'utime',
|
|
170
|
+
'timerfd_gettime',
|
|
171
|
+
'timerfd_settime',
|
|
172
|
+
'timer_gettime',
|
|
173
|
+
'timer_settime',
|
|
174
|
+
'fstatat',
|
|
175
|
+
'fstat',
|
|
176
|
+
'__fxstatat',
|
|
177
|
+
'__fxstat',
|
|
178
|
+
'lstat',
|
|
179
|
+
'__lxstat',
|
|
180
|
+
'stat',
|
|
181
|
+
'__xstat',
|
|
182
|
+
'struct itimerval',
|
|
183
|
+
'setitimer',
|
|
184
|
+
'getitimer',
|
|
185
|
+
'ntp_gettime',
|
|
186
|
+
'getrusage',
|
|
187
|
+
'wait3',
|
|
188
|
+
'wait4',
|
|
189
|
+
'adjtimex',
|
|
190
|
+
'ntp_adjtime',
|
|
191
|
+
'getutent_r',
|
|
192
|
+
'getutent',
|
|
193
|
+
'getutid_r',
|
|
194
|
+
'getutid',
|
|
195
|
+
'getutline_r',
|
|
196
|
+
'getutline',
|
|
197
|
+
'login',
|
|
198
|
+
'pututline',
|
|
199
|
+
'updwtmp',
|
|
200
|
+
'getutxent',
|
|
201
|
+
'getutxid',
|
|
202
|
+
'getutxline',
|
|
203
|
+
'pututxline'
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def parse_dump_config(config_name):
|
|
215
|
+
"""
|
|
216
|
+
Parse Y2038-related flags from cppcheck dump file configuration name.
|
|
217
|
+
|
|
218
|
+
This function analyzes the cppcheck dump file configuration name (which contains
|
|
219
|
+
preprocessor definitions extracted by cppcheck from project files like compile_commands.json)
|
|
220
|
+
to extract Y2038-related definitions. It looks for _TIME_BITS, _USE_TIME_BITS64, and
|
|
221
|
+
_FILE_OFFSET_BITS definitions and validates their values.
|
|
222
|
+
|
|
223
|
+
Args:
|
|
224
|
+
config_name (str): The cppcheck configuration name from dump file
|
|
225
|
+
(e.g., "_TIME_BITS=64;_FILE_OFFSET_BITS=64")
|
|
226
|
+
|
|
227
|
+
Returns:
|
|
228
|
+
dict: Dictionary containing Y2038-related flag information with keys:
|
|
229
|
+
- 'time_bits_defined' (bool): Whether _TIME_BITS is defined
|
|
230
|
+
- 'time_bits_value' (int|None): Value of _TIME_BITS (None if not defined)
|
|
231
|
+
- 'use_time_bits64_defined' (bool): Whether _USE_TIME_BITS64 is defined
|
|
232
|
+
- 'file_offset_bits_defined' (bool): Whether _FILE_OFFSET_BITS is defined
|
|
233
|
+
- 'file_offset_bits_value' (int|None): Value of _FILE_OFFSET_BITS (None if not defined)
|
|
234
|
+
|
|
235
|
+
Example:
|
|
236
|
+
>>> parse_dump_config("_TIME_BITS=64;_FILE_OFFSET_BITS=64")
|
|
237
|
+
{
|
|
238
|
+
'time_bits_defined': True,
|
|
239
|
+
'time_bits_value': 64,
|
|
240
|
+
'use_time_bits64_defined': False,
|
|
241
|
+
'file_offset_bits_defined': True,
|
|
242
|
+
'file_offset_bits_value': 64
|
|
243
|
+
}
|
|
244
|
+
"""
|
|
245
|
+
result = {
|
|
246
|
+
'time_bits_defined': False,
|
|
247
|
+
'time_bits_value': None,
|
|
248
|
+
'use_time_bits64_defined': False,
|
|
249
|
+
'file_offset_bits_defined': False,
|
|
250
|
+
'file_offset_bits_value': None
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
if not config_name:
|
|
254
|
+
return result
|
|
255
|
+
|
|
256
|
+
try:
|
|
257
|
+
# Check for _TIME_BITS=64 (correct value)
|
|
258
|
+
if re_flag_time_bits_64.search(config_name):
|
|
259
|
+
result['time_bits_defined'] = True
|
|
260
|
+
result['time_bits_value'] = Y2038_SAFE_TIME_BITS
|
|
261
|
+
else:
|
|
262
|
+
# Check for _TIME_BITS=other_value
|
|
263
|
+
match = re_flag_time_bits.search(config_name)
|
|
264
|
+
if match:
|
|
265
|
+
result['time_bits_defined'] = True
|
|
266
|
+
try:
|
|
267
|
+
result['time_bits_value'] = int(match.group(1))
|
|
268
|
+
except (ValueError, IndexError):
|
|
269
|
+
# Malformed _TIME_BITS value, treat as undefined
|
|
270
|
+
result['time_bits_defined'] = False
|
|
271
|
+
result['time_bits_value'] = None
|
|
272
|
+
|
|
273
|
+
# Check for _USE_TIME_BITS64
|
|
274
|
+
if re_flag_use_time_bits64.search(config_name):
|
|
275
|
+
result['use_time_bits64_defined'] = True
|
|
276
|
+
|
|
277
|
+
# Check for _FILE_OFFSET_BITS=64 (correct value)
|
|
278
|
+
if re_flag_file_offset_bits_64.search(config_name):
|
|
279
|
+
result['file_offset_bits_defined'] = True
|
|
280
|
+
result['file_offset_bits_value'] = Y2038_SAFE_FILE_OFFSET_BITS
|
|
281
|
+
else:
|
|
282
|
+
# Check for _FILE_OFFSET_BITS=other_value
|
|
283
|
+
match = re_flag_file_offset_bits.search(config_name)
|
|
284
|
+
if match:
|
|
285
|
+
result['file_offset_bits_defined'] = True
|
|
286
|
+
try:
|
|
287
|
+
result['file_offset_bits_value'] = int(match.group(1))
|
|
288
|
+
except (ValueError, IndexError):
|
|
289
|
+
# Malformed _FILE_OFFSET_BITS value, treat as undefined
|
|
290
|
+
result['file_offset_bits_defined'] = False
|
|
291
|
+
result['file_offset_bits_value'] = None
|
|
292
|
+
|
|
293
|
+
except (AttributeError, TypeError, ValueError):
|
|
294
|
+
# If any unexpected error occurs during parsing, return empty result
|
|
295
|
+
# This ensures the addon continues to work even with malformed configurations
|
|
296
|
+
# Note: We catch specific exceptions rather than broad Exception for better debugging
|
|
297
|
+
pass
|
|
298
|
+
|
|
299
|
+
return result
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
def check_y2038_safe(dumpfile, quiet=False):
|
|
303
|
+
"""
|
|
304
|
+
Main function to check Y2038 safety of C/C++ code from cppcheck dump files.
|
|
305
|
+
|
|
306
|
+
This function performs comprehensive Y2038 analysis including:
|
|
307
|
+
1. Extraction of Y2038-related compiler flags from cppcheck dump file configuration
|
|
308
|
+
2. Analysis of source code preprocessor directives
|
|
309
|
+
3. Warning suppression when proper Y2038 configuration is detected
|
|
310
|
+
4. Reporting of Y2038-unsafe symbols and configurations
|
|
311
|
+
|
|
312
|
+
The function implements a priority-based approach for Y2038 flag detection:
|
|
313
|
+
- Dump file configuration (from cppcheck's project parsing - highest priority)
|
|
314
|
+
- Source code #define directives (fallback)
|
|
315
|
+
|
|
316
|
+
Warning suppression occurs when both _TIME_BITS=64 AND _FILE_OFFSET_BITS=64
|
|
317
|
+
are detected from any source. When warnings are suppressed, an informational
|
|
318
|
+
message is displayed indicating the configuration source and suppression count.
|
|
319
|
+
|
|
320
|
+
Args:
|
|
321
|
+
dumpfile (str): Path to the cppcheck XML dump file (.dump extension)
|
|
322
|
+
quiet (bool, optional): If True, suppress informational messages. Defaults to False.
|
|
323
|
+
|
|
324
|
+
Returns:
|
|
325
|
+
bool: True if code is Y2038-safe, False if Y2038 issues were detected
|
|
326
|
+
|
|
327
|
+
Raises:
|
|
328
|
+
Exception: May raise exceptions from cppcheckdata parsing or file I/O operations
|
|
329
|
+
|
|
330
|
+
Example:
|
|
331
|
+
>>> check_y2038_safe("test.c.dump") # Normal operation
|
|
332
|
+
True
|
|
333
|
+
>>> check_y2038_safe("test.c.dump", quiet=True) # Suppress info messages
|
|
334
|
+
False
|
|
335
|
+
"""
|
|
336
|
+
# Assume that the code is Y2038 safe until proven otherwise
|
|
337
|
+
y2038safe = True
|
|
338
|
+
# load XML from .dump file
|
|
339
|
+
data = cppcheckdata.CppcheckData(dumpfile)
|
|
340
|
+
|
|
341
|
+
srcfile = data.files[0]
|
|
342
|
+
|
|
343
|
+
for cfg in data.iterconfigurations():
|
|
344
|
+
if not quiet:
|
|
345
|
+
print('Checking %s, config %s...' % (srcfile, cfg.name))
|
|
346
|
+
safe_ranges = []
|
|
347
|
+
safe = -1
|
|
348
|
+
time_bits_defined = False
|
|
349
|
+
srclinenr = 0
|
|
350
|
+
|
|
351
|
+
# Priority-based flag detection: dump file configuration > source code directives
|
|
352
|
+
# 1. Check dump file configuration (from cppcheck's project parsing - highest priority)
|
|
353
|
+
dump_config_flags = parse_dump_config(cfg.name)
|
|
354
|
+
# Initialize effective flags with dump file configuration
|
|
355
|
+
effective_flags = {
|
|
356
|
+
'time_bits_defined': dump_config_flags['time_bits_defined'],
|
|
357
|
+
'time_bits_value': dump_config_flags['time_bits_value'],
|
|
358
|
+
'use_time_bits64_defined': dump_config_flags['use_time_bits64_defined'],
|
|
359
|
+
'file_offset_bits_defined': dump_config_flags['file_offset_bits_defined'],
|
|
360
|
+
'file_offset_bits_value': dump_config_flags['file_offset_bits_value']
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
# Determine configuration source for reporting
|
|
364
|
+
config_source = None
|
|
365
|
+
has_dump_config = (dump_config_flags['time_bits_defined'] or
|
|
366
|
+
dump_config_flags['file_offset_bits_defined'] or
|
|
367
|
+
dump_config_flags['use_time_bits64_defined'])
|
|
368
|
+
if has_dump_config:
|
|
369
|
+
config_source = "cppcheck configuration"
|
|
370
|
+
|
|
371
|
+
# Track time_bits_defined for _USE_TIME_BITS64 validation
|
|
372
|
+
time_bits_defined = effective_flags['time_bits_defined']
|
|
373
|
+
|
|
374
|
+
# Check effective _TIME_BITS value (from dump file configuration)
|
|
375
|
+
if effective_flags['time_bits_defined']:
|
|
376
|
+
if effective_flags['time_bits_value'] != Y2038_SAFE_TIME_BITS:
|
|
377
|
+
fake_directive = type('FakeDirective', (), {
|
|
378
|
+
'file': srcfile, 'linenr': 0, 'column': 0,
|
|
379
|
+
'str': 'cppcheck configuration: _TIME_BITS=%s' % effective_flags['time_bits_value']
|
|
380
|
+
})()
|
|
381
|
+
cppcheckdata.reportError(fake_directive, 'error',
|
|
382
|
+
'_TIME_BITS must be defined equal to 64 (found in cppcheck configuration: _TIME_BITS=%s)' % effective_flags['time_bits_value'],
|
|
383
|
+
'y2038',
|
|
384
|
+
'type-bits-not-64')
|
|
385
|
+
y2038safe = False
|
|
386
|
+
|
|
387
|
+
# Check effective _FILE_OFFSET_BITS value (from dump file configuration)
|
|
388
|
+
if effective_flags['file_offset_bits_defined']:
|
|
389
|
+
if effective_flags['file_offset_bits_value'] != Y2038_SAFE_FILE_OFFSET_BITS:
|
|
390
|
+
fake_directive = type('FakeDirective', (), {
|
|
391
|
+
'file': srcfile, 'linenr': 0, 'column': 0,
|
|
392
|
+
'str': 'cppcheck configuration: _FILE_OFFSET_BITS=%s' % effective_flags['file_offset_bits_value']
|
|
393
|
+
})()
|
|
394
|
+
cppcheckdata.reportError(fake_directive, 'error',
|
|
395
|
+
'_FILE_OFFSET_BITS must be defined equal to 64 (found in cppcheck configuration: _FILE_OFFSET_BITS=%s)' % effective_flags['file_offset_bits_value'],
|
|
396
|
+
'y2038',
|
|
397
|
+
'file-offset-bits-not-64')
|
|
398
|
+
y2038safe = False
|
|
399
|
+
|
|
400
|
+
# Check effective _USE_TIME_BITS64 (from dump file configuration)
|
|
401
|
+
if effective_flags['use_time_bits64_defined']:
|
|
402
|
+
if not time_bits_defined:
|
|
403
|
+
# _USE_TIME_BITS64 defined without _TIME_BITS is problematic
|
|
404
|
+
fake_directive = type('FakeDirective', (), {
|
|
405
|
+
'file': srcfile, 'linenr': 0, 'column': 0,
|
|
406
|
+
'str': 'cppcheck configuration: _USE_TIME_BITS64'
|
|
407
|
+
})()
|
|
408
|
+
cppcheckdata.reportError(fake_directive, 'warning',
|
|
409
|
+
'_USE_TIME_BITS64 is defined in cppcheck configuration but _TIME_BITS was not',
|
|
410
|
+
'y2038',
|
|
411
|
+
'type-bits-undef')
|
|
412
|
+
y2038safe = False
|
|
413
|
+
else:
|
|
414
|
+
# _USE_TIME_BITS64 defined WITH _TIME_BITS - this is correct
|
|
415
|
+
safe = 0 # Start of file is safe
|
|
416
|
+
|
|
417
|
+
# 2. Fallback to source code directives when dump file configuration is not available
|
|
418
|
+
source_time_bits_defined = False # pylint: disable=unused-variable
|
|
419
|
+
source_file_offset_bits_defined = False # pylint: disable=unused-variable
|
|
420
|
+
source_file_offset_bits_value = None # pylint: disable=unused-variable
|
|
421
|
+
source_use_time_bits64_defined = False # pylint: disable=unused-variable
|
|
422
|
+
|
|
423
|
+
# Track which flags came from source code for mixed scenario reporting
|
|
424
|
+
source_flags_used = {
|
|
425
|
+
'time_bits': False,
|
|
426
|
+
'file_offset_bits': False,
|
|
427
|
+
'use_time_bits64': False
|
|
428
|
+
}
|
|
429
|
+
for directive in cfg.directives:
|
|
430
|
+
# track source line number
|
|
431
|
+
if directive.file == srcfile:
|
|
432
|
+
srclinenr = directive.linenr
|
|
433
|
+
|
|
434
|
+
# Process source code directives as fallback when dump config is not available
|
|
435
|
+
# check for correct _TIME_BITS if present
|
|
436
|
+
if re_define_time_bits_64.match(directive.str):
|
|
437
|
+
source_time_bits_defined = True
|
|
438
|
+
# Only use source directive if dump config doesn't define _TIME_BITS
|
|
439
|
+
if not effective_flags['time_bits_defined']:
|
|
440
|
+
effective_flags['time_bits_defined'] = True
|
|
441
|
+
effective_flags['time_bits_value'] = Y2038_SAFE_TIME_BITS
|
|
442
|
+
time_bits_defined = True
|
|
443
|
+
source_flags_used['time_bits'] = True
|
|
444
|
+
elif re_define_time_bits.match(directive.str):
|
|
445
|
+
source_time_bits_defined = False
|
|
446
|
+
# Only use source directive if dump config doesn't define _TIME_BITS
|
|
447
|
+
if not effective_flags['time_bits_defined']:
|
|
448
|
+
source_flags_used['time_bits'] = True
|
|
449
|
+
cppcheckdata.reportError(directive, 'error',
|
|
450
|
+
'_TIME_BITS must be defined equal to 64',
|
|
451
|
+
'y2038',
|
|
452
|
+
'type-bits-not-64')
|
|
453
|
+
y2038safe = False
|
|
454
|
+
elif re_undef_time_bits.match(directive.str):
|
|
455
|
+
source_time_bits_defined = False
|
|
456
|
+
# Only use source directive if dump config doesn't define _TIME_BITS
|
|
457
|
+
if not effective_flags['time_bits_defined']:
|
|
458
|
+
time_bits_defined = False
|
|
459
|
+
source_flags_used['time_bits'] = True
|
|
460
|
+
# check for correct _FILE_OFFSET_BITS if present
|
|
461
|
+
if re_define_file_offset_bits_64.match(directive.str):
|
|
462
|
+
source_file_offset_bits_defined = True
|
|
463
|
+
source_file_offset_bits_value = Y2038_SAFE_FILE_OFFSET_BITS
|
|
464
|
+
# Only use source directive if dump config doesn't define _FILE_OFFSET_BITS
|
|
465
|
+
if not effective_flags['file_offset_bits_defined']:
|
|
466
|
+
effective_flags['file_offset_bits_defined'] = True
|
|
467
|
+
effective_flags['file_offset_bits_value'] = Y2038_SAFE_FILE_OFFSET_BITS
|
|
468
|
+
source_flags_used['file_offset_bits'] = True
|
|
469
|
+
elif re_define_file_offset_bits.match(directive.str):
|
|
470
|
+
source_file_offset_bits_defined = False
|
|
471
|
+
# Only use source directive if dump config doesn't define _FILE_OFFSET_BITS
|
|
472
|
+
if not effective_flags['file_offset_bits_defined']:
|
|
473
|
+
source_flags_used['file_offset_bits'] = True
|
|
474
|
+
cppcheckdata.reportError(directive, 'error',
|
|
475
|
+
'_FILE_OFFSET_BITS must be defined equal to 64',
|
|
476
|
+
'y2038',
|
|
477
|
+
'file-offset-bits-not-64')
|
|
478
|
+
y2038safe = False
|
|
479
|
+
elif re_undef_file_offset_bits.match(directive.str):
|
|
480
|
+
source_file_offset_bits_defined = False
|
|
481
|
+
source_file_offset_bits_value = None
|
|
482
|
+
# Only use source directive if dump config doesn't define _FILE_OFFSET_BITS
|
|
483
|
+
if not effective_flags['file_offset_bits_defined']:
|
|
484
|
+
effective_flags['file_offset_bits_defined'] = False
|
|
485
|
+
effective_flags['file_offset_bits_value'] = None
|
|
486
|
+
source_flags_used['file_offset_bits'] = True
|
|
487
|
+
|
|
488
|
+
# check for _USE_TIME_BITS64 (un)definition
|
|
489
|
+
if re_define_use_time_bits64.match(directive.str):
|
|
490
|
+
safe = int(srclinenr)
|
|
491
|
+
source_use_time_bits64_defined = True
|
|
492
|
+
# Only use source directive if dump config doesn't define _USE_TIME_BITS64
|
|
493
|
+
if not effective_flags['use_time_bits64_defined']:
|
|
494
|
+
effective_flags['use_time_bits64_defined'] = True
|
|
495
|
+
source_flags_used['use_time_bits64'] = True
|
|
496
|
+
# warn about _TIME_BITS not being defined (check effective flags)
|
|
497
|
+
if not time_bits_defined:
|
|
498
|
+
cppcheckdata.reportError(directive, 'warning',
|
|
499
|
+
'_USE_TIME_BITS64 is defined but _TIME_BITS was not',
|
|
500
|
+
'y2038',
|
|
501
|
+
'type-bits-undef')
|
|
502
|
+
elif re_undef_use_time_bits64.match(directive.str):
|
|
503
|
+
unsafe = int(srclinenr)
|
|
504
|
+
source_use_time_bits64_defined = False
|
|
505
|
+
# Only use source directive if dump config doesn't define _USE_TIME_BITS64
|
|
506
|
+
if not effective_flags['use_time_bits64_defined']:
|
|
507
|
+
source_flags_used['use_time_bits64'] = True
|
|
508
|
+
# do we have a safe..unsafe area?
|
|
509
|
+
if unsafe > safe >= 0:
|
|
510
|
+
safe_ranges.append((safe, unsafe))
|
|
511
|
+
safe = -1
|
|
512
|
+
|
|
513
|
+
# check end of source beyond last directive
|
|
514
|
+
if len(cfg.tokenlist) > 0:
|
|
515
|
+
unsafe = int(cfg.tokenlist[-1].linenr)
|
|
516
|
+
if unsafe > safe >= 0:
|
|
517
|
+
safe_ranges.append((safe, unsafe))
|
|
518
|
+
|
|
519
|
+
# Determine if Y2038 warnings should be suppressed
|
|
520
|
+
# Require BOTH _TIME_BITS=64 AND _FILE_OFFSET_BITS=64 for complete Y2038 safety
|
|
521
|
+
y2038_safe_config = (
|
|
522
|
+
effective_flags['time_bits_defined'] and
|
|
523
|
+
effective_flags['time_bits_value'] == Y2038_SAFE_TIME_BITS and
|
|
524
|
+
effective_flags['file_offset_bits_defined'] and
|
|
525
|
+
effective_flags['file_offset_bits_value'] == Y2038_SAFE_FILE_OFFSET_BITS
|
|
526
|
+
)
|
|
527
|
+
|
|
528
|
+
# Update config_source for suppression reporting based on mixed scenarios
|
|
529
|
+
if y2038_safe_config:
|
|
530
|
+
# Determine configuration source for mixed scenarios
|
|
531
|
+
dump_flags_count = sum([
|
|
532
|
+
dump_config_flags['time_bits_defined'],
|
|
533
|
+
dump_config_flags['file_offset_bits_defined'],
|
|
534
|
+
dump_config_flags['use_time_bits64_defined']
|
|
535
|
+
])
|
|
536
|
+
source_flags_count = sum(source_flags_used.values())
|
|
537
|
+
|
|
538
|
+
if dump_flags_count > 0 and source_flags_count > 0:
|
|
539
|
+
# Mixed scenario: both dump config and source directives used
|
|
540
|
+
config_source = "mixed configuration (cppcheck configuration and source code directives)"
|
|
541
|
+
elif dump_flags_count > 0:
|
|
542
|
+
# Only dump config used
|
|
543
|
+
config_source = "cppcheck configuration"
|
|
544
|
+
elif source_flags_count > 0:
|
|
545
|
+
# Only source directives used
|
|
546
|
+
config_source = "source code directives"
|
|
547
|
+
else:
|
|
548
|
+
# Fallback (shouldn't happen if y2038_safe_config is True)
|
|
549
|
+
config_source = "configuration"
|
|
550
|
+
|
|
551
|
+
# go through all tokens
|
|
552
|
+
warnings_suppressed = 0
|
|
553
|
+
for token in cfg.tokenlist:
|
|
554
|
+
if token.str in id_Y2038:
|
|
555
|
+
is_in_safe_range = any(lower <= int(token.linenr) <= upper
|
|
556
|
+
for (lower, upper) in safe_ranges)
|
|
557
|
+
|
|
558
|
+
if not is_in_safe_range:
|
|
559
|
+
if y2038_safe_config:
|
|
560
|
+
# Count suppressed warnings but don't report them
|
|
561
|
+
warnings_suppressed += 1
|
|
562
|
+
else:
|
|
563
|
+
# Report the warning as before
|
|
564
|
+
cppcheckdata.reportError(token, 'warning',
|
|
565
|
+
token.str + ' is Y2038-unsafe',
|
|
566
|
+
'y2038',
|
|
567
|
+
'unsafe-call')
|
|
568
|
+
y2038safe = False
|
|
569
|
+
token = token.next
|
|
570
|
+
|
|
571
|
+
# Print suppression message if warnings were suppressed
|
|
572
|
+
if warnings_suppressed > 0 and config_source and not quiet:
|
|
573
|
+
print('Y2038 warnings suppressed: Found proper Y2038 configuration in %s (_TIME_BITS=%d and _FILE_OFFSET_BITS=%d)' % (config_source, Y2038_SAFE_TIME_BITS, Y2038_SAFE_FILE_OFFSET_BITS))
|
|
574
|
+
print('Suppressed %d Y2038-unsafe function warning(s)' % warnings_suppressed)
|
|
575
|
+
|
|
576
|
+
return y2038safe
|
|
577
|
+
|
|
578
|
+
|
|
579
|
+
def get_args_parser():
|
|
580
|
+
parser = cppcheckdata.ArgumentParser()
|
|
581
|
+
return parser
|
|
582
|
+
|
|
583
|
+
|
|
584
|
+
if __name__ == '__main__':
|
|
585
|
+
parser = get_args_parser()
|
|
586
|
+
args = parser.parse_args()
|
|
587
|
+
|
|
588
|
+
exit_code = 0
|
|
589
|
+
quiet = args.quiet or args.cli
|
|
590
|
+
|
|
591
|
+
if not args.dumpfile:
|
|
592
|
+
if not args.quiet:
|
|
593
|
+
print("no input files.")
|
|
594
|
+
sys.exit(0)
|
|
595
|
+
|
|
596
|
+
for dumpfile in args.dumpfile:
|
|
597
|
+
if not quiet:
|
|
598
|
+
print('Checking ' + dumpfile + '...')
|
|
599
|
+
|
|
600
|
+
check_y2038_safe(dumpfile, quiet)
|
|
601
|
+
|
|
602
|
+
sys.exit(cppcheckdata.EXIT_CODE)
|