Security and reliability fix. Recommended for all users. pana 160/160.
Undefined behavior parsing untrusted catalog data
The digit accumulators in AppStreamParser computed result * 10 + digit with no bound, so a long enough run of digits overflowed. Signed overflow is undefined behavior. UBSan confirmed it on the real code path:
AppStreamParser.cpp:57 runtime error: signed integer overflow:
999999999999999999 * 10 cannot be represented in type 'long long int'
AppStreamParser.cpp:37 runtime error: signed integer overflow:
999999999 * 10 cannot be represented in type 'int'
Both are reached from attribute values in a catalog downloaded over the network — <release timestamp="999…"> and <icon width="999…">. The same helper also parses priority, image and video dimensions, and icon scale.
Accumulation now saturates, so a hostile value is clamped rather than wrapped, and the parse stays total. Three regression tests cover it.
This was not caught earlier despite CI running a Debug/Release x asan/ubsan matrix, because no test fed an oversized number.
Unchecked gmtime_r
gmtime_r returns null for a time_t it cannot represent, which a saturated epoch reaches. The return value was ignored, leaving the std::tm zero-initialized and silently producing a 1900-01-01T00:00:00Z timestamp. An unrepresentable epoch now yields no timestamp.
Pinned static analysis
scripts/tidy.sh pins clang-tidy the way scripts/format.sh pins clang-format, and the CI clang-tidy job is no longer advisory.
Unpinned, results depended on which LLVM happened to be first on PATH. The version CI installed could not parse a current libstdc++ — it emitted 20 parse errors and stopped early — while also reporting a bugprone-use-after-move false positive on x = {} immediately after std::move(x), which is the documented way to restore a moved-from object. The pinned version is what found the gmtime_r defect above.
| Version | Parses host libstdc++ | use-after-move false positive |
Found gmtime_r defect |
|---|---|---|---|
| 18 | ✗ bails early | yes | no |
| 20 (pinned) | ✓ | no | ✓ |
| 22 | ✓ | no | no |
The gate passes --warnings-as-errors, because plain clang-tidy exits 0 even when it reports diagnostics.
Verification
152/152 C++ tests (three new) including asan and ubsan, 45/45 Dart, UBSan clean on both hostile inputs after the fix, clang-tidy clean at the pinned version, clang-format applied last, dart analyze --fatal-infos clean, dart pub publish --dry-run 0 warnings.
No API changes.
Full changelog: https://github.com/flatpak-minimal/appstream_dart/blob/v0.4.2/CHANGELOG.md