|
| 1 | +# README of the Y2038 cppcheck addon |
| 2 | + |
| 3 | +## Contents |
| 4 | + |
| 5 | +- [What is Y2038?](#what-is-y2038) |
| 6 | +- [What is the Y2038 cppcheck addon?](#what-is-the-y2038-cppcheck-addon) |
| 7 | +- [How does the Y2038 cppcheck addon work?](#how-does-the-y2038-cppcheck-addon-work) |
| 8 | +- [How to use the Y2038 cppcheck addon](#how-to-use-the-y2038-cppcheck-addon) |
| 9 | + |
| 10 | +--- |
| 11 | + |
| 12 | +## What is Y2038? |
| 13 | + |
| 14 | +In a few words: |
| 15 | + |
| 16 | +In Linux, the current date and time is kept as the number of seconds elapsed |
| 17 | +since the Unix epoch, that is, since January 1st, 1970 at 00:00:00 GMT. |
| 18 | + |
| 19 | +Most of the time, this representation is stored as a 32-bit signed quantity. |
| 20 | + |
| 21 | +On January 19th, 2038 at 03:14:07 GMT, such 32-bit representations will reach |
| 22 | +their maximum positive value. |
| 23 | + |
| 24 | +What happens then is unpredictable: system time might roll back to December |
| 25 | +13th, 1901 at 19:55:13, or it might keep running on until February 7th, 2106 |
| 26 | +at 06:28:15 GMT, or the computer may freeze, or just about anything you can |
| 27 | +think of, plus a few ones you can't. |
| 28 | + |
| 29 | +The workaround for this is to switch to a 64-bit signed representation of time |
| 30 | +as seconds from the Unix epoch. This representation will work for more than 250 |
| 31 | +billion years. |
| 32 | + |
| 33 | +Working around Y2038 requires fixing the Linux kernel, the C libraries, and |
| 34 | +any user code around which uses 32-bit epoch representations. |
| 35 | + |
| 36 | +There is Y2038-proofing work in progress on the Linux and GNU glibc front. |
| 37 | + |
| 38 | +## What is the Y2038 cppcheck addon? |
| 39 | + |
| 40 | +The Y2038 cppcheck addon is a tool to help detect code which might need fixing |
| 41 | +because it is Y2038-unsafe. This may be because it uses types or functions from |
| 42 | +GNU libc or from the Linux kernel which are known not to be Y2038-proof. |
| 43 | + |
| 44 | +## How does the Y2038 cppcheck addon work? |
| 45 | + |
| 46 | +The Y2038 cppcheck addon takes XML dumps produced by `cppcheck` from source code |
| 47 | +files and looks for the names of types or functions which are known to be Y2038- |
| 48 | +unsafe, and emits diagnostics whenever it finds one. |
| 49 | + |
| 50 | +Of course, this is of little use if your code uses a Y2038-proof glibc and |
| 51 | +correctly configured Y2038-proof time support. |
| 52 | + |
| 53 | +This is why `y2038.py` takes into account preprocessor directives like |
| 54 | +`_TIME_BITS`, `__USE_TIME_BITS64`, and `_FILE_OFFSET_BITS`. |
| 55 | + |
| 56 | +The addon now features comprehensive build system detection and compiler flag |
| 57 | +checking that eliminates false positives when projects are properly configured |
| 58 | +for Y2038 safety. This enables analysis of entire codebases without being |
| 59 | +overwhelmed by warnings from correctly configured code. |
| 60 | + |
| 61 | +### Key improvements in this version: |
| 62 | + |
| 63 | +* **Eliminate false positives**: Automatically suppress Y2038 warnings when proper |
| 64 | + configuration is detected (both `_TIME_BITS=64` AND `_FILE_OFFSET_BITS=64`) |
| 65 | + |
| 66 | +* **Comprehensive codebase analysis**: Run Y2038 checks across entire projects |
| 67 | + without manual flag specification - the addon discovers build configurations |
| 68 | + automatically |
| 69 | + |
| 70 | +* **Multi-build-system support**: Detects Y2038 flags from Makefile, CMake, |
| 71 | + Meson, Autotools, and other build systems with hierarchical directory search |
| 72 | + |
| 73 | +* **Smart warning suppression**: When proper Y2038 configuration is found, |
| 74 | + displays informational messages instead of false warnings |
| 75 | + |
| 76 | +* **Enterprise-ready**: Suitable for CI/CD pipelines and large-scale code analysis |
| 77 | + |
| 78 | +### Build System Detection: |
| 79 | +The addon automatically searches for and parses the following build files: |
| 80 | +- Makefiles (`Makefile`, `makefile`, `GNUmakefile`, `*.mk`) |
| 81 | +- CMake files (`CMakeLists.txt`, `*.cmake`) |
| 82 | +- Configure scripts (`configure`, `configure.ac`, `configure.in`) |
| 83 | +- Meson build files (`meson.build`) |
| 84 | +- Other build systems (`BUILD`, `BUILD.bazel`, etc.) |
| 85 | + |
| 86 | +The addon searches up to 5 directory levels from the source file location to |
| 87 | +find relevant build files and extracts Y2038-related compiler definitions. |
| 88 | + |
| 89 | +### Warning Suppression: |
| 90 | +When proper Y2038 configuration is detected (both `_TIME_BITS=64` AND |
| 91 | +`_FILE_OFFSET_BITS=64` defined), Y2038 warnings are automatically suppressed |
| 92 | +with an informational message indicating the source of the configuration. |
| 93 | + |
| 94 | +### Priority order for Y2038 flag detection (highest to lowest): |
| 95 | +1. Build system files (`Makefile`, `CMakeLists.txt`, etc.) |
| 96 | +2. Compiler flags (`-D` options passed to `cppcheck`) |
| 97 | +3. Source code `#define` directives |
| 98 | + |
| 99 | +`_TIME_BITS` is defined equal to 64 by user code when it wants 64-bit time |
| 100 | +support from the GNU glibc. Code which does not define `_TIME_BITS` equal to 64 |
| 101 | +(or defines it to something else than 64) runs a risk of not being Y2038-proof. |
| 102 | + |
| 103 | +`__USE_TIME_BITS64` is defined by the GNU glibc when it actually provides 64-bit |
| 104 | +time support. When this is defined, then all glibc symbols, barring bugs, are |
| 105 | +Y2038-proof (but your code might have its own Y2038 bugs, if it handles signed |
| 106 | +32-bit Unix epoch values). |
| 107 | + |
| 108 | +The Y2038 cppcheck performs the following checks: |
| 109 | + |
| 110 | + 1. Upon meeting a definition for `_TIME_BITS`, if that definition does not |
| 111 | + set it equal to 64, this error diagnostic is emitted: |
| 112 | + |
| 113 | + ``` |
| 114 | + Error: _TIME_BITS must be defined equal to 64 |
| 115 | + ``` |
| 116 | +
|
| 117 | + This case is very unlikely but might result from a typo, so pointing |
| 118 | + it out is quite useful. Note that definitions of `_TIME_BITS` as an |
| 119 | + expression evaluating to 64 will be flagged too. |
| 120 | +
|
| 121 | + 2. Upon meeting a definition for `_USE_TIME_BITS64`, if `_TIME_BITS` is not |
| 122 | + defined equal to 64, this information diagnostic is emitted: |
| 123 | +
|
| 124 | + ``` |
| 125 | + Warning: _USE_TIME_BITS64 is defined but _TIME_BITS was not |
| 126 | + ``` |
| 127 | +
|
| 128 | + This reflects the fact that even though the glibc checked default to |
| 129 | + 64-bit time support, this was not requested by the user code, and |
| 130 | + therefore the user code might fail Y2038 if built against a glibc |
| 131 | + which defaults to 32-bit time support. |
| 132 | +
|
| 133 | + 3. Upon meeting a symbol (type or function) which is known to be Y2038- |
| 134 | + unsafe, if proper Y2038 configuration is not detected, this warning |
| 135 | + diagnostic is emitted: |
| 136 | +
|
| 137 | + ``` |
| 138 | + Warning: <symbol> is Y2038-unsafe |
| 139 | + ``` |
| 140 | +
|
| 141 | + This reflects the fact that the user code is referring to a symbol |
| 142 | + which, when glibc defaults to 32-bit time support, might fail Y2038. |
| 143 | + |
| 144 | + However, if proper Y2038 configuration is detected (both `_TIME_BITS=64` |
| 145 | + AND `_FILE_OFFSET_BITS=64`), these warnings are suppressed and an |
| 146 | + informational message is displayed instead. |
| 147 | +
|
| 148 | +General note: `y2038.py` will handle multiple configurations, and will |
| 149 | +emit diagnostics for each configuration in turn. |
| 150 | +
|
| 151 | +## How to use the Y2038 cppcheck addon |
| 152 | +
|
| 153 | +### **Comprehensive Codebase Analysis** |
| 154 | +
|
| 155 | +The enhanced Y2038 addon is designed for analyzing entire codebases efficiently: |
| 156 | +
|
| 157 | +```sh |
| 158 | +# Analyze all C files in a project - addon will detect build system configs automatically |
| 159 | +cppcheck --addon=y2038 . |
| 160 | +
|
| 161 | +# For projects with proper Y2038 configuration, you'll see suppression messages instead of false warnings: |
| 162 | +# Y2038 warnings suppressed: Found proper Y2038 configuration in build system (_TIME_BITS=64 and _FILE_OFFSET_BITS=64) |
| 163 | +``` |
| 164 | + |
| 165 | +### **CI/CD Integration** |
| 166 | + |
| 167 | +This addon is now suitable for continuous integration workflows: |
| 168 | + |
| 169 | +```sh |
| 170 | +# Example CI script |
| 171 | +#!/bin/bash |
| 172 | +find . -name "*.c" -exec cppcheck --dump {} \; |
| 173 | +python3 addons/y2038.py $(find . -name "*.dump") |
| 174 | + |
| 175 | +# Returns non-zero exit code only for actual Y2038 issues, |
| 176 | +# not for properly configured projects |
| 177 | +``` |
| 178 | + |
| 179 | +### **Basic Usage** |
| 180 | + |
| 181 | +The Y2038 cppcheck addon is used like any other cppcheck addon: |
| 182 | + |
| 183 | +```sh |
| 184 | +cppcheck --dump file1.c [ file2.c [...]] |
| 185 | +y2038.py file1.c.dump [ file2.c.dump [...]] |
| 186 | +``` |
| 187 | +
|
| 188 | +To use compiler flags for Y2038 checking: |
| 189 | +
|
| 190 | +```sh |
| 191 | +cppcheck --dump -D_TIME_BITS=64 -D_USE_TIME_BITS64 file1.c |
| 192 | +y2038.py file1.c.dump |
| 193 | +``` |
| 194 | +
|
| 195 | +For automatic build system detection (recommended): |
| 196 | +
|
| 197 | +```sh |
| 198 | +cppcheck --dump file1.c # No flags needed - addon detects from build files |
| 199 | +y2038.py file1.c.dump |
| 200 | +``` |
| 201 | +
|
| 202 | +The addon will automatically: |
| 203 | +1. Search for build system files (`Makefile`, `CMakeLists.txt`, etc.) |
| 204 | +2. Extract Y2038-related compiler definitions |
| 205 | +3. Validate `_TIME_BITS` and `_USE_TIME_BITS64` configurations |
| 206 | +4. Report any Y2038-unsafe configurations found in build files |
| 207 | +
|
| 208 | +Example build system configurations that will be detected: |
| 209 | +
|
| 210 | +Makefile: |
| 211 | +```makefile |
| 212 | +CPPFLAGS = -D_TIME_BITS=64 -D_FILE_OFFSET_BITS=64 |
| 213 | +``` |
| 214 | +
|
| 215 | +CMakeLists.txt: |
| 216 | +```cmake |
| 217 | +add_definitions(-D_TIME_BITS=64) |
| 218 | +add_definitions(-D_FILE_OFFSET_BITS=64) |
| 219 | +``` |
| 220 | +
|
| 221 | +meson.build: |
| 222 | +```meson |
| 223 | +add_global_arguments('-D_TIME_BITS=64', language : 'c') |
| 224 | +add_project_arguments('-D_FILE_OFFSET_BITS=64', language : 'c') |
| 225 | +``` |
| 226 | +
|
| 227 | +When both `_TIME_BITS=64` and `_FILE_OFFSET_BITS=64` are found, Y2038 warnings |
| 228 | +will be suppressed with a message like: |
| 229 | +``` |
| 230 | +Y2038 warnings suppressed: Found proper Y2038 configuration in build system (_TIME_BITS=64 and _FILE_OFFSET_BITS=64) |
| 231 | +Suppressed X Y2038-unsafe function warning(s) |
| 232 | +``` |
| 233 | +
|
| 234 | +Sample test C files are provided: |
| 235 | +
|
| 236 | +- `test/y2038-test-1-bad-time-bits.c` # Source code with wrong `_TIME_BITS` |
| 237 | +- `test/y2038-test-2-no-time-bits.c` # Source code missing `_TIME_BITS` |
| 238 | +- `test/y2038-test-3-no-use-time-bits.c` # Missing `_USE_TIME_BITS64` |
| 239 | +- `test/y2038-test-4-good.c` # Proper Y2038 setup in source |
| 240 | +- `test/y2038-test-5-good-no-time-used.c` # No time functions used |
| 241 | +- `test/y2038-test-compiler-flags.c` # Shared test file for compiler flag scenarios: |
| 242 | + # - Proper Y2038 config (`-D_TIME_BITS=64 -D_FILE_OFFSET_BITS=64 -D_USE_TIME_BITS64`) |
| 243 | + # - Wrong `_TIME_BITS` value (`-D_TIME_BITS=32`) |
| 244 | + # - Incomplete config (`-D_USE_TIME_BITS64` only) |
| 245 | +
|
| 246 | +These cover the cases described above. You can run them through cppcheck |
| 247 | +and y2038.py to see for yourself how the addon diagnostics look like. If |
| 248 | +this README is not outdated (and if it is, feel free to submit a patch), |
| 249 | +you can run `cppcheck` on these files as on any others: |
| 250 | +
|
| 251 | +```sh |
| 252 | +cppcheck --dump addons/test/y2038/y2038-*.c |
| 253 | +python3 addons/y2038.py addons/test/y2038/y2038-*.dump |
| 254 | +``` |
| 255 | +
|
| 256 | +For testing compiler flag functionality (using the shared test file): |
| 257 | +
|
| 258 | +```sh |
| 259 | +# Test proper Y2038 configuration |
| 260 | +cppcheck --dump -D_TIME_BITS=64 -D_FILE_OFFSET_BITS=64 -D_USE_TIME_BITS64 addons/test/y2038/y2038-test-compiler-flags.c |
| 261 | +python3 addons/y2038.py addons/test/y2038/y2038-test-compiler-flags.c.dump |
| 262 | +
|
| 263 | +# Test wrong _TIME_BITS value |
| 264 | +cppcheck --dump -D_TIME_BITS=32 addons/test/y2038/y2038-test-compiler-flags.c |
| 265 | +python3 addons/y2038.py addons/test/y2038/y2038-test-compiler-flags.c.dump |
| 266 | +
|
| 267 | +# Test incomplete configuration (should produce warnings) |
| 268 | +cppcheck --dump -D_USE_TIME_BITS64 addons/test/y2038/y2038-test-compiler-flags.c |
| 269 | +python3 addons/y2038.py addons/test/y2038/y2038-test-compiler-flags.c.dump |
| 270 | +``` |
| 271 | +
|
| 272 | +If you have not installed cppcheck yet, you will have to run these |
| 273 | +commands from the root of the cppcheck repository: |
| 274 | +
|
| 275 | +```sh |
| 276 | +make |
| 277 | +sudo make install |
| 278 | +./cppcheck --dump addons/test/y2038/y2038-*.c |
| 279 | +PYTHONPATH=addons python3 addons/y2038.py addons/test/y2038/y2038-*.c.dump |
| 280 | +``` |
| 281 | +
|
| 282 | +In both cases, `y2038.py` execution should result in the following: |
| 283 | +
|
| 284 | +``` |
| 285 | +Checking addons/y2038/test/y2038-test-1-bad-time-bits.c.dump... |
| 286 | +Checking addons/y2038/test/y2038-test-1-bad-time-bits.c.dump, config ""... |
| 287 | +Checking addons/y2038/test/y2038-test-2-no-time-bits.c.dump... |
| 288 | +Checking addons/y2038/test/y2038-test-2-no-time-bits.c.dump, config ""... |
| 289 | +Checking addons/y2038/test/y2038-test-3-no-use-time-bits.c.dump... |
| 290 | +Checking addons/y2038/test/y2038-test-3-no-use-time-bits.c.dump, config ""... |
| 291 | +Checking addons/y2038/test/y2038-test-4-good.c.dump... |
| 292 | +Checking addons/y2038/test/y2038-test-4-good.c.dump, config ""... |
| 293 | +# Configuration "": |
| 294 | +# Configuration "": |
| 295 | +[addons/y2038/test/y2038-test-1-bad-time-bits.c:8]: (error) _TIME_BITS must be defined equal to 64 |
| 296 | +[addons/y2038/test/y2038-inc.h:9]: (warning) _USE_TIME_BITS64 is defined but _TIME_BITS was not |
| 297 | +[addons/y2038/test/y2038-test-1-bad-time-bits.c:10]: (information) addons/y2038/test/y2038-inc.h was included from here |
| 298 | +[addons/y2038/test/y2038-inc.h:9]: (warning) _USE_TIME_BITS64 is defined but _TIME_BITS was not |
| 299 | +[addons/y2038/test/y2038-test-2-no-time-bits.c:8]: (information) addons/y2038/test/y2038-inc.h was included from here |
| 300 | +[addons/y2038/test/y2038-test-3-no-use-time-bits.c:13]: (warning) timespec is Y2038-unsafe |
| 301 | +[addons/y2038/test/y2038-test-3-no-use-time-bits.c:15]: (warning) clock_gettime is Y2038-unsafe |
| 302 | +``` |
| 303 | +
|
| 304 | +Note: `y2038.py` recognizes option `--template` as `cppcheck` does, including |
| 305 | +pre-defined templates 'gcc', 'vs' and 'edit'. The short form `-t` is also |
| 306 | +recognized. |
0 commit comments