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.
Files changed (84) hide show
  1. cppcheck/__init__.py +55 -0
  2. cppcheck/cppcheck-2.20.0.tar.gz +0 -0
  3. cppcheck/data/addons/__init__.py +0 -0
  4. cppcheck/data/addons/cppcheck.py +41 -0
  5. cppcheck/data/addons/cppcheckdata.py +1727 -0
  6. cppcheck/data/addons/findcasts.py +32 -0
  7. cppcheck/data/addons/misc.py +163 -0
  8. cppcheck/data/addons/misra.py +5153 -0
  9. cppcheck/data/addons/misra_9.py +559 -0
  10. cppcheck/data/addons/naming.py +92 -0
  11. cppcheck/data/addons/namingng.py +420 -0
  12. cppcheck/data/addons/runaddon.py +16 -0
  13. cppcheck/data/addons/threadsafety.py +350 -0
  14. cppcheck/data/addons/y2038.py +602 -0
  15. cppcheck/data/cfg/avr.cfg +402 -0
  16. cppcheck/data/cfg/bento4.cfg +142 -0
  17. cppcheck/data/cfg/boost.cfg +1284 -0
  18. cppcheck/data/cfg/bsd.cfg +567 -0
  19. cppcheck/data/cfg/cairo.cfg +90 -0
  20. cppcheck/data/cfg/cppcheck-lib.cfg +72 -0
  21. cppcheck/data/cfg/cppunit.cfg +48 -0
  22. cppcheck/data/cfg/dpdk.cfg +11 -0
  23. cppcheck/data/cfg/embedded_sql.cfg +4 -0
  24. cppcheck/data/cfg/emscripten.cfg +108 -0
  25. cppcheck/data/cfg/ginac.cfg +12848 -0
  26. cppcheck/data/cfg/gnu.cfg +1738 -0
  27. cppcheck/data/cfg/googletest.cfg +62 -0
  28. cppcheck/data/cfg/gtk.cfg +23086 -0
  29. cppcheck/data/cfg/icu.cfg +221 -0
  30. cppcheck/data/cfg/kde.cfg +92 -0
  31. cppcheck/data/cfg/libcerror.cfg +203 -0
  32. cppcheck/data/cfg/libcurl.cfg +487 -0
  33. cppcheck/data/cfg/libsigc++.cfg +36 -0
  34. cppcheck/data/cfg/lua.cfg +316 -0
  35. cppcheck/data/cfg/mfc.cfg +271 -0
  36. cppcheck/data/cfg/microsoft_atl.cfg +40 -0
  37. cppcheck/data/cfg/microsoft_sal.cfg +490 -0
  38. cppcheck/data/cfg/microsoft_unittest.cfg +20 -0
  39. cppcheck/data/cfg/motif.cfg +318 -0
  40. cppcheck/data/cfg/nspr.cfg +38 -0
  41. cppcheck/data/cfg/ntl.cfg +6907 -0
  42. cppcheck/data/cfg/opencv2.cfg +132 -0
  43. cppcheck/data/cfg/opengl.cfg +581 -0
  44. cppcheck/data/cfg/openmp.cfg +157 -0
  45. cppcheck/data/cfg/openssl.cfg +174 -0
  46. cppcheck/data/cfg/pcre.cfg +165 -0
  47. cppcheck/data/cfg/posix.cfg +6445 -0
  48. cppcheck/data/cfg/protobuf.cfg +10 -0
  49. cppcheck/data/cfg/python.cfg +674 -0
  50. cppcheck/data/cfg/qt.cfg +5502 -0
  51. cppcheck/data/cfg/ruby.cfg +142 -0
  52. cppcheck/data/cfg/sdl.cfg +354 -0
  53. cppcheck/data/cfg/selinux.cfg +3621 -0
  54. cppcheck/data/cfg/sfml.cfg +301 -0
  55. cppcheck/data/cfg/sqlite3.cfg +1571 -0
  56. cppcheck/data/cfg/std.cfg +9215 -0
  57. cppcheck/data/cfg/tinyxml2.cfg +37 -0
  58. cppcheck/data/cfg/vcl.cfg +4 -0
  59. cppcheck/data/cfg/windows.cfg +17237 -0
  60. cppcheck/data/cfg/wxsqlite3.cfg +1955 -0
  61. cppcheck/data/cfg/wxsvg.cfg +16905 -0
  62. cppcheck/data/cfg/wxwidgets.cfg +17313 -0
  63. cppcheck/data/cfg/zephyr.cfg +113 -0
  64. cppcheck/data/cfg/zlib.cfg +1450 -0
  65. cppcheck/data/cppcheck-htmlreport +1157 -0
  66. cppcheck/data/cppcheck.exe +0 -0
  67. cppcheck/data/platforms/aix_ppc64.xml +18 -0
  68. cppcheck/data/platforms/arm32-wchar_t2.xml +18 -0
  69. cppcheck/data/platforms/arm32-wchar_t4.xml +18 -0
  70. cppcheck/data/platforms/arm64-wchar_t2.xml +18 -0
  71. cppcheck/data/platforms/arm64-wchar_t4.xml +18 -0
  72. cppcheck/data/platforms/avr8.xml +18 -0
  73. cppcheck/data/platforms/cray_sv1.xml +18 -0
  74. cppcheck/data/platforms/elbrus-e1cp.xml +18 -0
  75. cppcheck/data/platforms/mips32.xml +18 -0
  76. cppcheck/data/platforms/msp430_eabi_large_datamodel.xml +18 -0
  77. cppcheck/data/platforms/pic16.xml +18 -0
  78. cppcheck/data/platforms/pic8-enhanced.xml +18 -0
  79. cppcheck/data/platforms/pic8.xml +18 -0
  80. cppcheck_py-2.20.0.dist-info/METADATA +76 -0
  81. cppcheck_py-2.20.0.dist-info/RECORD +84 -0
  82. cppcheck_py-2.20.0.dist-info/WHEEL +5 -0
  83. cppcheck_py-2.20.0.dist-info/entry_points.txt +4 -0
  84. 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)