Commit Graph

12780 Commits

Author SHA1 Message Date
Mathias Vorreiter Pedersen
662e74924b C++: (Bugfix 1) There should be a callable representing the source code even if there is a summarized version. 2025-01-28 13:59:16 +00:00
Mathias Vorreiter Pedersen
01d7ab93e2 C++: Add consistency check to the MaD folder. 2025-01-28 13:59:14 +00:00
Erik Krogh Kristensen
f0755bfb5d Merge pull request #18601 from erik-krogh/del-deps-jan-2025
All: delete outdated deprecations
2025-01-28 13:31:41 +01:00
Geoffrey White
6337f5a08b Merge pull request #18586 from geoffw0/floatguards
C++: Test and (perhaps) fix an issue with guards on floating point comparisons.
2025-01-28 09:05:13 +00:00
erik-krogh
a1afa20d4b add change-notes 2025-01-27 22:43:13 +01:00
erik-krogh
bd8ed1dc04 cpp: revert two cpp dataflow deprecations that take more work 2025-01-27 22:16:54 +01:00
erik-krogh
34f5f61a10 all: use my script to delete outdated deprecations 2025-01-27 22:16:48 +01:00
Mathias Vorreiter Pedersen
4e44201ba8 C++: Remap calls to source functions to the summarized function. 2025-01-27 16:58:53 +00:00
Mathias Vorreiter Pedersen
98265dda7b Revert "C++: Don't generate dataflow nodes for instructions inside summarized callables."
This reverts commit fc39df28b0.
2025-01-27 16:58:46 +00:00
Jeroen Ketema
37b67dd9eb C++: Update stats file 2025-01-27 15:42:35 +01:00
Jeroen Ketema
f49d8209e5 C++: Add upgrade and downgrade scripts 2025-01-27 13:32:00 +01:00
Mathias Vorreiter Pedersen
67a905141c Update cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaInternalsCommon.qll
Co-authored-by: Jeroen Ketema <93738568+jketema@users.noreply.github.com>
2025-01-27 10:55:56 +00:00
Jeroen Ketema
a32cfdab9f C++: Support mixed typedefs and usings 2025-01-27 11:43:17 +01:00
Geoffrey White
67a746eff1 Update cpp/ql/lib/semmle/code/cpp/controlflow/IRGuards.qll
Co-authored-by: Jeroen Ketema <93738568+jketema@users.noreply.github.com>
2025-01-27 10:41:50 +00:00
Mathias Vorreiter Pedersen
ad80b36074 C++: Don't generate parameter nodes for bodyless parameters when there is a summary of the enclosing function. 2025-01-24 20:16:04 +00:00
Mathias Vorreiter Pedersen
cda629b204 C++: Accept test changes. Notice the consistency failure. 2025-01-24 20:13:21 +00:00
Mathias Vorreiter Pedersen
de3b111f2f C++: Map a parameter node to the summarized callable if it exists. 2025-01-24 20:08:16 +00:00
Mathias Vorreiter Pedersen
fc39df28b0 C++: Don't generate dataflow nodes for instructions inside summarized callables. 2025-01-24 20:05:19 +00:00
Geoffrey White
06bd394695 C++: Add a note for the other predicates as well. 2025-01-24 17:52:13 +00:00
Geoffrey White
1f962004a9 C++: Add a note in the QLDoc for comparesEq. 2025-01-24 17:52:03 +00:00
Geoffrey White
7664fd16e7 C++: Add more test cases for guards. 2025-01-24 17:51:45 +00:00
Jeroen Ketema
2e33a4287f C++: Apply review suggestion 2025-01-24 16:12:16 +01:00
Jeroen Ketema
4c256d17ae C++: Fix join-order problem in UserType::getADeclarationEntry
Before on `LRMPUT/PUTSLAM`:
```
Evaluated recursive predicate UserType::UserType.getADeclarationEntry/0#cea44e2f@7ce3a4hu in 22069ms on iteration 2 (delta size: 379076853).
Evaluated relational algebra for predicate UserType::UserType.getADeclarationEntry/0#cea44e2f@7ce3a4hu on iteration 2 running pipeline standard with tuple counts:
           126825  ~32%    {2} r1 = JOIN `UserType::UserType.getADeclarationEntry/0#cea44e2f#prev_delta` WITH Class::Class#9afdbffd ON FIRST 1 OUTPUT Lhs.0, Lhs.1
        379076853  ~97%    {2}    | JOIN WITH `Class::Class.isConstructedFrom/1#dispred#390e01c8_10#join_rhs` ON FIRST 1 OUTPUT Rhs.1, Lhs.1
        379076853  ~97%    {2}    | JOIN WITH UserType::UserType#21e9e463 ON FIRST 1 OUTPUT Lhs.0, Lhs.1
                           {2}    | AND NOT `UserType::UserType.getADeclarationEntry/0#cea44e2f#prev`(FIRST 2)
        379076853  ~96%    {2}    | SCAN OUTPUT In.1, In.0
                           {2}    | AND NOT `_Class::Class#9afdbffd_Class::Class.isConstructedFrom/1#dispred#390e01c8_10#join_rhs_ResolveClass::r__#antijoin_rhs`(FIRST 2)
        379076853  ~97%    {2}    | SCAN OUTPUT In.1, In.0
                           return r1

Evaluated named local _Class::Class#9afdbffd_Class::Class.isConstructedFrom/1#dispred#390e01c8_10#join_rhs_ResolveClass::r__#antijoin_rhs@L0#7ce3a in 7459ms on iteration 2 (size: 0).
Evaluated relational algebra for predicate _Class::Class#9afdbffd_Class::Class.isConstructedFrom/1#dispred#390e01c8_10#join_rhs_ResolveClass::r__#antijoin_rhs@L0#7ce3a on iteration 2 running pipeline main with tuple counts:
           126825  ~32%    {2} r1 = JOIN `UserType::UserType.getADeclarationEntry/0#cea44e2f#prev_delta` WITH Class::Class#9afdbffd ON FIRST 1 OUTPUT Lhs.0, Lhs.1
        379076853  ~97%    {2}    | JOIN WITH `Class::Class.isConstructedFrom/1#dispred#390e01c8_10#join_rhs` ON FIRST 1 OUTPUT Rhs.1, Lhs.1
        379076853  ~97%    {2}    | JOIN WITH UserType::UserType#21e9e463 ON FIRST 1 OUTPUT Lhs.0, Lhs.1
        379076853  ~97%    {2}    | AND NOT `UserType::UserType.getADeclarationEntry/0#cea44e2f#prev`(FIRST 2)

                0   ~0%    {2} r2 = r1 AND NOT usertypes_0#antijoin_rhs(FIRST 1)
                0   ~0%    {2}    | JOIN WITH type_decls_1#join_rhs ON FIRST 1 OUTPUT Lhs.1, Lhs.0

        379077929  ~95%    {3} r3 = JOIN r1 WITH `ResolveClass::resolveClass/1#ea47deee_10#join_rhs` ON FIRST 1 OUTPUT Rhs.1, Lhs.1, Lhs.0
                0   ~0%    {2}    | JOIN WITH type_decls_1#join_rhs ON FIRST 1 OUTPUT Lhs.1, Lhs.2

                0   ~0%    {2} r4 = r2 UNION r3
                           return r4

Evaluated named local _Class::Class#9afdbffd_Class::Class.isConstructedFrom/1#dispred#390e01c8_10#join_rhs_ResolveClass::r__#antijoin_rhs@L0#7ce3a in 1031ms on iteration 3 (size: 0).
Evaluated relational algebra for predicate _Class::Class#9afdbffd_Class::Class.isConstructedFrom/1#dispred#390e01c8_10#join_rhs_ResolveClass::r__#antijoin_rhs@L0#7ce3a on iteration 3 running pipeline main with tuple counts:
        190114100   ~0%    {2} r1 = JOIN `UserType::UserType.getADeclarationEntry/0#cea44e2f#prev_delta` WITH Class::Class#9afdbffd ON FIRST 1 OUTPUT Lhs.0, Lhs.1
                0   ~0%    {2}    | JOIN WITH `Class::Class.isConstructedFrom/1#dispred#390e01c8_10#join_rhs` ON FIRST 1 OUTPUT Rhs.1, Lhs.1
                0   ~0%    {2}    | JOIN WITH UserType::UserType#21e9e463 ON FIRST 1 OUTPUT Lhs.0, Lhs.1
                0   ~0%    {2}    | AND NOT `UserType::UserType.getADeclarationEntry/0#cea44e2f#prev`(FIRST 2)

                0   ~0%    {2} r2 = r1 AND NOT usertypes_0#antijoin_rhs(FIRST 1)
                0   ~0%    {2}    | JOIN WITH type_decls_1#join_rhs ON FIRST 1 OUTPUT Lhs.1, Lhs.0

                0   ~0%    {3} r3 = JOIN r1 WITH `ResolveClass::resolveClass/1#ea47deee_10#join_rhs` ON FIRST 1 OUTPUT Rhs.1, Lhs.1, Lhs.0
                0   ~0%    {2}    | JOIN WITH type_decls_1#join_rhs ON FIRST 1 OUTPUT Lhs.1, Lhs.2

                0   ~0%    {2} r4 = r2 UNION r3
                           return r4

Pipeline base for UserType::UserType.getADeclarationEntry/0#cea44e2f@7ce3a4hu was evaluated in 1 iterations totaling 149ms (delta sizes total: 224004).
         149171    ~17%    {1} r1 = JOIN type_decls_1#join_rhs WITH `ResolveClass::resolveClass/1#ea47deee` ON FIRST 1 OUTPUT Rhs.1
         125649     ~0%    {1}    | JOIN WITH UserType::UserType#21e9e463 ON FIRST 1 OUTPUT Lhs.0
        1811817  ~1075%    {2}    | JOIN WITH `ResolveClass::resolveClass/1#ea47deee_10#join_rhs` ON FIRST 1 OUTPUT Rhs.1, Lhs.0
        1812281  ~1172%    {2}    | JOIN WITH type_decls_10#join_rhs ON FIRST 1 OUTPUT Lhs.1, Rhs.1
                           return r1

Pipeline standard for UserType::UserType.getADeclarationEntry/0#cea44e2f@7ce3a4hu was evaluated in 1 iterations totaling 22069ms (delta sizes total: 379076853).
           126825  ~32%    {2} r1 = JOIN `UserType::UserType.getADeclarationEntry/0#cea44e2f#prev_delta` WITH Class::Class#9afdbffd ON FIRST 1 OUTPUT Lhs.0, Lhs.1
        379076853  ~97%    {2}    | JOIN WITH `Class::Class.isConstructedFrom/1#dispred#390e01c8_10#join_rhs` ON FIRST 1 OUTPUT Rhs.1, Lhs.1
        379076853  ~97%    {2}    | JOIN WITH UserType::UserType#21e9e463 ON FIRST 1 OUTPUT Lhs.0, Lhs.1
                           {2}    | AND NOT `UserType::UserType.getADeclarationEntry/0#cea44e2f#prev`(FIRST 2)
        379076853  ~96%    {2}    | SCAN OUTPUT In.1, In.0
                           {2}    | AND NOT `_Class::Class#9afdbffd_Class::Class.isConstructedFrom/1#dispred#390e01c8_10#join_rhs_ResolveClass::r__#antijoin_rhs`(FIRST 2)
        379076853  ~97%    {2}    | SCAN OUTPUT In.1, In.0
                           return r1

Pipeline main for _Class::Class#9afdbffd_Class::Class.isConstructedFrom/1#dispred#390e01c8_10#join_rhs_ResolveClass::r__#antijoin_rhs@L0#7ce3a was evaluated in 2 iterations totaling 8490ms (sizes total: 0).
        190240925   ~0%    {2} r1 = JOIN `UserType::UserType.getADeclarationEntry/0#cea44e2f#prev_delta` WITH Class::Class#9afdbffd ON FIRST 1 OUTPUT Lhs.0, Lhs.1
        379076853  ~97%    {2}    | JOIN WITH `Class::Class.isConstructedFrom/1#dispred#390e01c8_10#join_rhs` ON FIRST 1 OUTPUT Rhs.1, Lhs.1
        379076853  ~97%    {2}    | JOIN WITH UserType::UserType#21e9e463 ON FIRST 1 OUTPUT Lhs.0, Lhs.1
        379076853  ~97%    {2}    | AND NOT `UserType::UserType.getADeclarationEntry/0#cea44e2f#prev`(FIRST 2)

                0   ~0%    {2} r2 = r1 AND NOT usertypes_0#antijoin_rhs(FIRST 1)
                0   ~0%    {2}    | JOIN WITH type_decls_1#join_rhs ON FIRST 1 OUTPUT Lhs.1, Lhs.0

        379077929  ~95%    {3} r3 = JOIN r1 WITH `ResolveClass::resolveClass/1#ea47deee_10#join_rhs` ON FIRST 1 OUTPUT Rhs.1, Lhs.1, Lhs.0
                0   ~0%    {2}    | JOIN WITH type_decls_1#join_rhs ON FIRST 1 OUTPUT Lhs.1, Lhs.2

                0   ~0%    {2} r4 = r2 UNION r3
                           return r4
```

After:
```
[2025-01-24 15:22:19] Evaluated non-recursive predicate UserType::UserType.getADeclarationEntryBase/0#dispred#d07c0e9a@82645fgi in 8ms (size: 149661).
Evaluated relational algebra for predicate UserType::UserType.getADeclarationEntryBase/0#dispred#d07c0e9a@82645fgi with tuple counts:
        149661  ~5%    {2} r1 = JOIN `_ResolveClass::resolveClass/1#ea47deee_type_decls#shared` WITH UserType::UserType#21e9e463 ON FIRST 1 OUTPUT Lhs.0, Lhs.1
                       return r1

[2025-01-24 15:22:19] Evaluated non-recursive predicate project#UserType::UserType.getADeclarationEntryBase/0#dispred#d07c0e9a@22da38r1 in 10ms (size: 124540).
Evaluated relational algebra for predicate project#UserType::UserType.getADeclarationEntryBase/0#dispred#d07c0e9a@22da38r1 with tuple counts:
        149661  ~17%    {1} r1 = SCAN `UserType::UserType.getADeclarationEntryBase/0#dispred#d07c0e9a` OUTPUT In.0
        124540   ~0%    {1}    | STREAM DEDUP
                        return r1

[2025-01-24 15:22:20] Evaluated non-recursive predicate Class::Class.isConstructedFrom/1#dispred#390e01c8_10#join_rhs@9c5150lt in 91ms (size: 764244).
Evaluated relational algebra for predicate Class::Class.isConstructedFrom/1#dispred#390e01c8_10#join_rhs@9c5150lt with tuple counts:
        764244  ~2%    {2} r1 = SCAN `Class::Class.isConstructedFrom/1#dispred#390e01c8` OUTPUT In.1, In.0
                       return r1

Evaluated recursive predicate UserType::UserType.getADeclarationEntry/0#cea44e2f#fb@d5a154u4 in 8ms on iteration 1 (delta size: 25561).
Evaluated relational algebra for predicate UserType::UserType.getADeclarationEntry/0#cea44e2f#fb@d5a154u4 on iteration 1 running pipeline base with tuple counts:
        149661  ~2%    {2} r1 = SCAN `UserType::UserType.getADeclarationEntryBase/0#dispred#d07c0e9a` OUTPUT In.1, In.0
         25561  ~6%    {2}    | JOIN WITH type_def ON FIRST 1 OUTPUT Lhs.1, Lhs.0
                       return r1

Evaluated recursive predicate UserType::UserType.getADeclarationEntry/0#cea44e2f#fb@d5a154u4 in 108ms on iteration 2 (delta size: 763236).
Evaluated relational algebra for predicate UserType::UserType.getADeclarationEntry/0#cea44e2f#fb@d5a154u4 on iteration 2 running pipeline standard with tuple counts:
          3655  ~0%    {2} r1 = JOIN `UserType::UserType.getADeclarationEntry/0#cea44e2f#fb#prev_delta` WITH Class::Class#9afdbffd ON FIRST 1 OUTPUT Lhs.0, Lhs.1
        763236  ~1%    {2}    | JOIN WITH `Class::Class.isConstructedFrom/1#dispred#390e01c8_10#join_rhs` ON FIRST 1 OUTPUT Rhs.1, Lhs.1
        763236  ~1%    {2}    | AND NOT `UserType::UserType.getADeclarationEntry/0#cea44e2f#fb#prev`(FIRST 2)
        763236  ~1%    {2}    | AND NOT `project#UserType::UserType.getADeclarationEntryBase/0#dispred#d07c0e9a`(FIRST 1)
                       return r1

Pipeline base for UserType::UserType.getADeclarationEntry/0#cea44e2f#fb@d5a154u4 was evaluated in 1 iterations totaling 8ms (delta sizes total: 25561).
        149661  ~2%    {2} r1 = SCAN `UserType::UserType.getADeclarationEntryBase/0#dispred#d07c0e9a` OUTPUT In.1, In.0
         25561  ~6%    {2}    | JOIN WITH type_def ON FIRST 1 OUTPUT Lhs.1, Lhs.0
                       return r1

Pipeline standard for UserType::UserType.getADeclarationEntry/0#cea44e2f#fb@d5a154u4 was evaluated in 1 iterations totaling 108ms (delta sizes total: 763236).
          3655  ~0%    {2} r1 = JOIN `UserType::UserType.getADeclarationEntry/0#cea44e2f#fb#prev_delta` WITH Class::Class#9afdbffd ON FIRST 1 OUTPUT Lhs.0, Lhs.1
        763236  ~1%    {2}    | JOIN WITH `Class::Class.isConstructedFrom/1#dispred#390e01c8_10#join_rhs` ON FIRST 1 OUTPUT Rhs.1, Lhs.1
        763236  ~1%    {2}    | AND NOT `UserType::UserType.getADeclarationEntry/0#cea44e2f#fb#prev`(FIRST 2)
        763236  ~1%    {2}    | AND NOT `project#UserType::UserType.getADeclarationEntryBase/0#dispred#d07c0e9a`(FIRST 1)
                       return r1
```
2025-01-24 15:24:13 +01:00
Jeroen Ketema
4311553fa0 Merge pull request #18578 from aschackmull/cpp/join-order-fix-taintedallocationsize
C++: Fix join order problem in TaintedAllocationSize.
2025-01-23 17:16:03 +01:00
Mathias Vorreiter Pedersen
ccb28ed0b3 Merge pull request #18556 from MathiasVP/remove-conflation-from-pure-functions
C++: Remove pointer/pointee conflation from models of "pure" functions
2025-01-23 15:50:39 +00:00
Mathias Vorreiter Pedersen
7792839a25 C++: Add a 'isLocaleParameter' and clean up the model a bit. 2025-01-23 13:56:00 +00:00
Mathias Vorreiter Pedersen
67e3b69996 C++: Move comment. 2025-01-23 13:49:13 +00:00
Mathias Vorreiter Pedersen
fb12847360 Update cpp/ql/lib/semmle/code/cpp/models/implementations/Pure.qll
Co-authored-by: Simon Friis Vindum <paldepind@github.com>
2025-01-23 13:48:44 +00:00
Mathias Vorreiter Pedersen
2cdb52cad2 C++: Accept test changes after previous commit. 2025-01-23 13:46:47 +00:00
Mathias Vorreiter Pedersen
e0f2f1dd80 Update cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp
Co-authored-by: Simon Friis Vindum <paldepind@github.com>
2025-01-23 13:41:48 +00:00
Anders Schack-Mulligen
1a4d21777d C++: Fix join order problem in TaintedAllocationSize. 2025-01-23 14:20:23 +01:00
Jeroen Ketema
68ec4b66e7 C++: Fix join-order problem found on IncorrectCheckScanf.ql
Before on `silentearth/curl2`:

```
Evaluated recursive predicate IRGuards::Cached::unary_compares_eq/5#7aa979d8@e3b01fca in 26109ms on iteration 2 (delta size: 4020).
Evaluated relational algebra for predicate IRGuards::Cached::unary_compares_eq/5#7aa979d8@e3b01fca on iteration 2 running pipeline standard with tuple counts:
                 0   ~0%    {5} r1 = JOIN `IRGuards::Cached::unary_compares_eq/5#7aa979d8#prev_delta` WITH `IRGuards::Cached::BuiltinExpectCallValueNumber.getCondition/0#dispred#9b2b5da2_10#join_rhs` ON FIRST 1 OUTPUT Rhs.1, Lhs.1, Lhs.2, Lhs.3, Lhs.4

           1835651   ~2%    {5} r2 = SCAN `IRGuards::Cached::unary_compares_eq/5#7aa979d8#prev_delta` OUTPUT In.4, In.0, In.1, In.2, In.3
           1832833   ~0%    {5}    | JOIN WITH `IRGuards::AbstractValue.getDualValue/0#dispred#bfb2631d` ON FIRST 1 OUTPUT Lhs.1, Lhs.2, Lhs.3, Lhs.4, Rhs.1
              3996   ~0%    {5}    | JOIN WITH `IRGuards::Cached::LogicalNotValueNumber.getUnary/0#dispred#b2251f1f_10#join_rhs` ON FIRST 1 OUTPUT Rhs.1, Lhs.1, Lhs.2, Lhs.3, Lhs.4

           1835651   ~7%    {5} r3 = SCAN `IRGuards::Cached::unary_compares_eq/5#7aa979d8#prev_delta` OUTPUT In.1, In.0, In.2, In.3, In.4
           1835651   ~1%    {5}    | JOIN WITH `Operand::Operand.getAnyDef/0#dispred#8dbe2fb8` ON FIRST 1 OUTPUT Rhs.1, Lhs.1, Lhs.2, Lhs.3, Lhs.4

                 0   ~0%    {5} r4 = JOIN r3 WITH project#Instruction::PointerSubInstruction#0d109780 ON FIRST 1 OUTPUT Lhs.0, Lhs.1, Lhs.2, Lhs.3, Lhs.4
                 0   ~0%    {6}    | JOIN WITH `Instruction::BinaryInstruction.getLeftOperand/0#dispred#c8432d08` ON FIRST 1 OUTPUT Lhs.0, Lhs.1, Lhs.2, Lhs.3, Lhs.4, Rhs.1
                 0   ~0%    {6}    | JOIN WITH `Instruction::BinaryInstruction.getRight/0#dispred#1f78e436` ON FIRST 1 OUTPUT Rhs.1, Lhs.1, Lhs.2, Lhs.3, Lhs.4, Lhs.5
                 0   ~0%    {7}    | JOIN WITH `IRGuards::Cached::int_value/1#f9d7a458` ON FIRST 1 OUTPUT Lhs.1, Lhs.5, _, Lhs.3, Lhs.4, Lhs.2, Rhs.1
                 0   ~0%    {5}    | REWRITE WITH Out.2 := (In.5 + In.6) KEEPING 5

                23  ~76%    {5} r5 = JOIN r3 WITH Instruction::SubInstruction#fc619901 ON FIRST 1 OUTPUT Lhs.0, Lhs.1, Lhs.2, Lhs.3, Lhs.4
                22  ~56%    {6}    | JOIN WITH `Instruction::BinaryInstruction.getLeftOperand/0#dispred#c8432d08` ON FIRST 1 OUTPUT Lhs.0, Lhs.1, Lhs.2, Lhs.3, Lhs.4, Rhs.1
                22  ~56%    {6}    | JOIN WITH `Instruction::BinaryInstruction.getRight/0#dispred#1f78e436` ON FIRST 1 OUTPUT Rhs.1, Lhs.1, Lhs.2, Lhs.3, Lhs.4, Lhs.5
                 0   ~0%    {7}    | JOIN WITH `IRGuards::Cached::int_value/1#f9d7a458` ON FIRST 1 OUTPUT Lhs.1, Lhs.5, _, Lhs.3, Lhs.4, Lhs.2, Rhs.1
                 0   ~0%    {5}    | REWRITE WITH Out.2 := (In.5 + In.6) KEEPING 5

                 0   ~0%    {5} r6 = JOIN r3 WITH project#Instruction::PointerAddInstruction#5233892c ON FIRST 1 OUTPUT Lhs.0, Lhs.1, Lhs.2, Lhs.3, Lhs.4

                 0   ~0%    {6} r7 = JOIN r6 WITH `Instruction::BinaryInstruction.getLeftOperand/0#dispred#c8432d08` ON FIRST 1 OUTPUT Lhs.0, Lhs.1, Lhs.2, Lhs.3, Lhs.4, Rhs.1
                 0   ~0%    {6}    | JOIN WITH `Instruction::BinaryInstruction.getRight/0#dispred#1f78e436` ON FIRST 1 OUTPUT Rhs.1, Lhs.1, Lhs.2, Lhs.3, Lhs.4, Lhs.5
                 0   ~0%    {7}    | JOIN WITH `IRGuards::Cached::int_value/1#f9d7a458` ON FIRST 1 OUTPUT Lhs.1, Lhs.5, _, Lhs.3, Lhs.4, Lhs.2, Rhs.1
                 0   ~0%    {5}    | REWRITE WITH Out.2 := (In.5 - In.6) KEEPING 5

                 0   ~0%    {6} r8 = JOIN r6 WITH `Instruction::BinaryInstruction.getRightOperand/0#dispred#9ca710da` ON FIRST 1 OUTPUT Lhs.0, Lhs.1, Lhs.2, Lhs.3, Lhs.4, Rhs.1
                 0   ~0%    {6}    | JOIN WITH `Instruction::BinaryInstruction.getLeft/0#dispred#5cf78406` ON FIRST 1 OUTPUT Rhs.1, Lhs.1, Lhs.2, Lhs.3, Lhs.4, Lhs.5
                 0   ~0%    {7}    | JOIN WITH `IRGuards::Cached::int_value/1#f9d7a458` ON FIRST 1 OUTPUT Lhs.1, Lhs.5, _, Lhs.3, Lhs.4, Lhs.2, Rhs.1
                 0   ~0%    {5}    | REWRITE WITH Out.2 := (In.5 - In.6) KEEPING 5

                12  ~49%    {5} r9 = JOIN r3 WITH Instruction::AddInstruction#7f8fb455 ON FIRST 1 OUTPUT Lhs.0, Lhs.1, Lhs.2, Lhs.3, Lhs.4

                12  ~49%    {6} r10 = JOIN r9 WITH `Instruction::BinaryInstruction.getLeftOperand/0#dispred#c8432d08` ON FIRST 1 OUTPUT Lhs.0, Lhs.1, Lhs.2, Lhs.3, Lhs.4, Rhs.1
                12  ~71%    {6}    | JOIN WITH `Instruction::BinaryInstruction.getRight/0#dispred#1f78e436` ON FIRST 1 OUTPUT Rhs.1, Lhs.1, Lhs.2, Lhs.3, Lhs.4, Lhs.5
                 0   ~0%    {7}    | JOIN WITH `IRGuards::Cached::int_value/1#f9d7a458` ON FIRST 1 OUTPUT Lhs.1, Lhs.5, _, Lhs.3, Lhs.4, Lhs.2, Rhs.1
                 0   ~0%    {5}    | REWRITE WITH Out.2 := (In.5 - In.6) KEEPING 5

                12  ~49%    {6} r11 = JOIN r9 WITH `Instruction::BinaryInstruction.getRightOperand/0#dispred#9ca710da` ON FIRST 1 OUTPUT Lhs.0, Lhs.1, Lhs.2, Lhs.3, Lhs.4, Rhs.1
                12  ~49%    {6}    | JOIN WITH `Instruction::BinaryInstruction.getLeft/0#dispred#5cf78406` ON FIRST 1 OUTPUT Rhs.1, Lhs.1, Lhs.2, Lhs.3, Lhs.4, Lhs.5
                 0   ~0%    {7}    | JOIN WITH `IRGuards::Cached::int_value/1#f9d7a458` ON FIRST 1 OUTPUT Lhs.1, Lhs.5, _, Lhs.3, Lhs.4, Lhs.2, Rhs.1
                 0   ~0%    {5}    | REWRITE WITH Out.2 := (In.5 - In.6) KEEPING 5

                 0   ~0%    {5} r12 = JOIN r1 WITH `IRGuards::Cached::BuiltinExpectCallValueNumber.getAUse/0#dispred#23233591` ON FIRST 1 OUTPUT Rhs.1, Lhs.1, Lhs.2, Lhs.3, Lhs.4
                 0   ~0%    {6}    | JOIN WITH `IRGuards::Cached::CompareValueNumber.hasOperands/2#dispred#7aa36763_102#join_rhs` ON FIRST 1 OUTPUT Rhs.1, Lhs.1, Lhs.2, Lhs.3, Lhs.4, Rhs.2

                 0   ~0%    {6} r13 = JOIN r12 WITH project#IRGuards::Cached::CompareNEValueNumber#1aeec1bd ON FIRST 1 OUTPUT Lhs.5, Lhs.1, Lhs.2, Lhs.3, Lhs.0, Lhs.4

                 0   ~0%    {6} r14 = JOIN r12 WITH project#IRGuards::Cached::CompareEQValueNumber#994b6833 ON FIRST 1 OUTPUT Lhs.4, Lhs.1, Lhs.2, Lhs.3, Lhs.0, Lhs.5
                 0   ~0%    {6}    | JOIN WITH `IRGuards::AbstractValue.getDualValue/0#dispred#bfb2631d_10#join_rhs` ON FIRST 1 OUTPUT Lhs.5, Lhs.1, Lhs.2, Lhs.3, Lhs.4, Rhs.1

                 0   ~0%    {6} r15 = r13 UNION r14
                 0   ~0%    {7}    | JOIN WITH `Operand::Operand.getAnyDef/0#dispred#8dbe2fb8` ON FIRST 1 OUTPUT Rhs.1, _, Lhs.1, Lhs.2, Lhs.3, Lhs.4, Lhs.5
                 0   ~0%    {7}    | REWRITE WITH Out.1 := 0
                 0   ~0%    {5}    | JOIN WITH `IRGuards::Cached::int_value/1#f9d7a458` ON FIRST 2 OUTPUT Lhs.5, Lhs.2, Lhs.3, Lhs.4, Lhs.6

        1901910478   ~1%    {5} r16 = JOIN `IRGuards::Cached::unary_compares_eq/5#7aa979d8#prev_delta` WITH `ValueNumberingInternal::tvalueNumber/1#f03b58f9_10#join_rhs` ON FIRST 1 OUTPUT Rhs.1, Lhs.1, Lhs.2, Lhs.3, Lhs.4
        1902015678   ~4%    {5}    | JOIN WITH `Operand::Operand.getDef/0#dispred#a70e8079_10#join_rhs` ON FIRST 1 OUTPUT Rhs.1, Lhs.1, Lhs.2, Lhs.3, Lhs.4
        1902015678   ~3%    {6}    | JOIN WITH `Operand::Operand.getDef/0#dispred#a70e8079` ON FIRST 1 OUTPUT Rhs.1, Lhs.1, Lhs.2, Lhs.3, Lhs.4, Lhs.0
        1901976207   ~4%    {5}    | JOIN WITH `IRGuards::Cached::isConvertedBool/1#9a130da2` ON FIRST 1 OUTPUT Lhs.5, Lhs.1, Lhs.2, Lhs.3, Lhs.4
                74  ~10%    {6}    | JOIN WITH `IRGuards::Cached::CompareValueNumber.hasOperands/2#dispred#7aa36763_102#join_rhs` ON FIRST 1 OUTPUT Rhs.1, Lhs.1, Lhs.2, Lhs.3, Lhs.4, Rhs.2

                54  ~10%    {6} r17 = JOIN r16 WITH project#IRGuards::Cached::CompareNEValueNumber#1aeec1bd ON FIRST 1 OUTPUT Lhs.5, Lhs.1, Lhs.2, Lhs.3, Lhs.0, Lhs.4

                20   ~0%    {6} r18 = JOIN r16 WITH project#IRGuards::Cached::CompareEQValueNumber#994b6833 ON FIRST 1 OUTPUT Lhs.4, Lhs.1, Lhs.2, Lhs.3, Lhs.0, Lhs.5
                20   ~0%    {6}    | JOIN WITH `IRGuards::AbstractValue.getDualValue/0#dispred#bfb2631d` ON FIRST 1 OUTPUT Lhs.5, Lhs.1, Lhs.2, Lhs.3, Lhs.4, Rhs.1

                74   ~5%    {6} r19 = r17 UNION r18
                74   ~5%    {7}    | JOIN WITH `Operand::Operand.getDef/0#dispred#a70e8079` ON FIRST 1 OUTPUT Rhs.1, _, Lhs.1, Lhs.2, Lhs.3, Lhs.4, Lhs.5
                74   ~4%    {7}    | REWRITE WITH Out.1 := 0
                66   ~0%    {5}    | JOIN WITH `IRGuards::Cached::int_value/1#f9d7a458` ON FIRST 2 OUTPUT Lhs.5, Lhs.2, Lhs.3, Lhs.4, Lhs.6

              4062   ~0%    {5} r20 = r1 UNION r2 UNION r4 UNION r5 UNION r7 UNION r8 UNION r10 UNION r11 UNION r15 UNION r19
              4020   ~0%    {5}    | AND NOT `IRGuards::Cached::unary_compares_eq/5#7aa979d8#prev`(FIRST 5)
                            return r20
```

After:
```
[2025-01-22 14:50:44] Evaluated non-recursive predicate _IRGuards::Cached::CompareValueNumber.hasOperands/2#dispred#7aa36763_102#join_rhs_IRGuards::Cached::__#join_rhs@25668753 in 36ms (size: 47).
Evaluated relational algebra for predicate _IRGuards::Cached::CompareValueNumber.hasOperands/2#dispred#7aa36763_102#join_rhs_IRGuards::Cached::__#join_rhs@25668753 with tuple counts:
        285951  ~0%    {4} r1 = JOIN `IRGuards::Cached::CompareValueNumber.hasOperands/2#dispred#7aa36763_102#join_rhs` WITH `Operand::Operand.getDef/0#dispred#a70e8079` ON FIRST 1 OUTPUT Rhs.1, Lhs.1, Lhs.0, Lhs.2
            47  ~2%    {3}    | JOIN WITH `IRGuards::Cached::isConvertedBool/1#9a130da2` ON FIRST 1 OUTPUT Lhs.2, Lhs.1, Lhs.3
            47  ~0%    {3}    | JOIN WITH `Operand::Operand.getDef/0#dispred#a70e8079` ON FIRST 1 OUTPUT Rhs.1, Lhs.1, Lhs.2
            47  ~0%    {3}    | JOIN WITH `ValueNumberingInternal::tvalueNumber/1#f03b58f9` ON FIRST 1 OUTPUT Rhs.1, Lhs.1, Lhs.2
                       return r1
                       Evaluated recursive predicate IRGuards::Cached::unary_compares_eq/5#7aa979d8@a808bbfb in 63ms on iteration 2 (delta size: 4020).
Evaluated relational algebra for predicate IRGuards::Cached::unary_compares_eq/5#7aa979d8@a808bbfb on iteration 2 running pipeline standard with tuple counts:
              0   ~0%    {5} r1 = JOIN `IRGuards::Cached::unary_compares_eq/5#7aa979d8#prev_delta` WITH `IRGuards::Cached::BuiltinExpectCallValueNumber.getCondition/0#dispred#9b2b5da2_10#join_rhs` ON FIRST 1 OUTPUT Rhs.1, Lhs.1, Lhs.2, Lhs.3, Lhs.4

        1881864  ~10%    {5} r2 = SCAN `IRGuards::Cached::unary_compares_eq/5#7aa979d8#prev_delta` OUTPUT In.4, In.0, In.1, In.2, In.3
        1879046   ~4%    {5}    | JOIN WITH `IRGuards::AbstractValue.getDualValue/0#dispred#bfb2631d` ON FIRST 1 OUTPUT Lhs.1, Lhs.2, Lhs.3, Lhs.4, Rhs.1
           3986   ~0%    {5}    | JOIN WITH `IRGuards::Cached::LogicalNotValueNumber.getUnary/0#dispred#b2251f1f_10#join_rhs` ON FIRST 1 OUTPUT Rhs.1, Lhs.1, Lhs.2, Lhs.3, Lhs.4

        1881864  ~11%    {5} r3 = SCAN `IRGuards::Cached::unary_compares_eq/5#7aa979d8#prev_delta` OUTPUT In.1, In.0, In.2, In.3, In.4
        1881864   ~2%    {5}    | JOIN WITH `Operand::Operand.getAnyDef/0#dispred#8dbe2fb8` ON FIRST 1 OUTPUT Rhs.1, Lhs.1, Lhs.2, Lhs.3, Lhs.4

              0   ~0%    {5} r4 = JOIN r3 WITH project#Instruction::PointerSubInstruction#0d109780 ON FIRST 1 OUTPUT Lhs.0, Lhs.1, Lhs.2, Lhs.3, Lhs.4
              0   ~0%    {6}    | JOIN WITH `Instruction::BinaryInstruction.getLeftOperand/0#dispred#c8432d08` ON FIRST 1 OUTPUT Lhs.0, Lhs.1, Lhs.2, Lhs.3, Lhs.4, Rhs.1
              0   ~0%    {6}    | JOIN WITH `Instruction::BinaryInstruction.getRight/0#dispred#1f78e436` ON FIRST 1 OUTPUT Rhs.1, Lhs.1, Lhs.2, Lhs.3, Lhs.4, Lhs.5
              0   ~0%    {7}    | JOIN WITH `IRGuards::Cached::int_value/1#f9d7a458` ON FIRST 1 OUTPUT Lhs.1, Lhs.5, _, Lhs.3, Lhs.4, Lhs.2, Rhs.1
              0   ~0%    {5}    | REWRITE WITH Out.2 := (In.5 + In.6) KEEPING 5

             16  ~14%    {5} r5 = JOIN r3 WITH Instruction::SubInstruction#fc619901 ON FIRST 1 OUTPUT Lhs.0, Lhs.1, Lhs.2, Lhs.3, Lhs.4
             16  ~14%    {6}    | JOIN WITH `Instruction::BinaryInstruction.getLeftOperand/0#dispred#c8432d08` ON FIRST 1 OUTPUT Lhs.0, Lhs.1, Lhs.2, Lhs.3, Lhs.4, Rhs.1
             16  ~14%    {6}    | JOIN WITH `Instruction::BinaryInstruction.getRight/0#dispred#1f78e436` ON FIRST 1 OUTPUT Rhs.1, Lhs.1, Lhs.2, Lhs.3, Lhs.4, Lhs.5
              0   ~0%    {7}    | JOIN WITH `IRGuards::Cached::int_value/1#f9d7a458` ON FIRST 1 OUTPUT Lhs.1, Lhs.5, _, Lhs.3, Lhs.4, Lhs.2, Rhs.1
              0   ~0%    {5}    | REWRITE WITH Out.2 := (In.5 + In.6) KEEPING 5

              0   ~0%    {5} r6 = JOIN r3 WITH project#Instruction::PointerAddInstruction#5233892c ON FIRST 1 OUTPUT Lhs.0, Lhs.1, Lhs.2, Lhs.3, Lhs.4

              0   ~0%    {6} r7 = JOIN r6 WITH `Instruction::BinaryInstruction.getLeftOperand/0#dispred#c8432d08` ON FIRST 1 OUTPUT Lhs.0, Lhs.1, Lhs.2, Lhs.3, Lhs.4, Rhs.1
              0   ~0%    {6}    | JOIN WITH `Instruction::BinaryInstruction.getRight/0#dispred#1f78e436` ON FIRST 1 OUTPUT Rhs.1, Lhs.1, Lhs.2, Lhs.3, Lhs.4, Lhs.5
              0   ~0%    {7}    | JOIN WITH `IRGuards::Cached::int_value/1#f9d7a458` ON FIRST 1 OUTPUT Lhs.1, Lhs.5, _, Lhs.3, Lhs.4, Lhs.2, Rhs.1
              0   ~0%    {5}    | REWRITE WITH Out.2 := (In.5 - In.6) KEEPING 5

              0   ~0%    {6} r8 = JOIN r6 WITH `Instruction::BinaryInstruction.getRightOperand/0#dispred#9ca710da` ON FIRST 1 OUTPUT Lhs.0, Lhs.1, Lhs.2, Lhs.3, Lhs.4, Rhs.1
              0   ~0%    {6}    | JOIN WITH `Instruction::BinaryInstruction.getLeft/0#dispred#5cf78406` ON FIRST 1 OUTPUT Rhs.1, Lhs.1, Lhs.2, Lhs.3, Lhs.4, Lhs.5
              0   ~0%    {7}    | JOIN WITH `IRGuards::Cached::int_value/1#f9d7a458` ON FIRST 1 OUTPUT Lhs.1, Lhs.5, _, Lhs.3, Lhs.4, Lhs.2, Rhs.1
              0   ~0%    {5}    | REWRITE WITH Out.2 := (In.5 - In.6) KEEPING 5

              8   ~0%    {5} r9 = JOIN r3 WITH Instruction::AddInstruction#7f8fb455 ON FIRST 1 OUTPUT Lhs.0, Lhs.1, Lhs.2, Lhs.3, Lhs.4

              8   ~0%    {6} r10 = JOIN r9 WITH `Instruction::BinaryInstruction.getLeftOperand/0#dispred#c8432d08` ON FIRST 1 OUTPUT Lhs.0, Lhs.1, Lhs.2, Lhs.3, Lhs.4, Rhs.1
              8   ~0%    {6}    | JOIN WITH `Instruction::BinaryInstruction.getRight/0#dispred#1f78e436` ON FIRST 1 OUTPUT Rhs.1, Lhs.1, Lhs.2, Lhs.3, Lhs.4, Lhs.5
              0   ~0%    {7}    | JOIN WITH `IRGuards::Cached::int_value/1#f9d7a458` ON FIRST 1 OUTPUT Lhs.1, Lhs.5, _, Lhs.3, Lhs.4, Lhs.2, Rhs.1
              0   ~0%    {5}    | REWRITE WITH Out.2 := (In.5 - In.6) KEEPING 5

              8   ~0%    {6} r11 = JOIN r9 WITH `Instruction::BinaryInstruction.getRightOperand/0#dispred#9ca710da` ON FIRST 1 OUTPUT Lhs.0, Lhs.1, Lhs.2, Lhs.3, Lhs.4, Rhs.1
              8   ~0%    {6}    | JOIN WITH `Instruction::BinaryInstruction.getLeft/0#dispred#5cf78406` ON FIRST 1 OUTPUT Rhs.1, Lhs.1, Lhs.2, Lhs.3, Lhs.4, Lhs.5
              0   ~0%    {7}    | JOIN WITH `IRGuards::Cached::int_value/1#f9d7a458` ON FIRST 1 OUTPUT Lhs.1, Lhs.5, _, Lhs.3, Lhs.4, Lhs.2, Rhs.1
              0   ~0%    {5}    | REWRITE WITH Out.2 := (In.5 - In.6) KEEPING 5

             70   ~6%    {6} r12 = JOIN `IRGuards::Cached::unary_compares_eq/5#7aa979d8#prev_delta` WITH `_IRGuards::Cached::CompareValueNumber.hasOperands/2#dispred#7aa36763_102#join_rhs_IRGuards::Cached::__#join_rhs` ON FIRST 1 OUTPUT Rhs.1, Rhs.2, Lhs.1, Lhs.2, Lhs.3, Lhs.4

             50   ~2%    {6} r13 = JOIN r12 WITH project#IRGuards::Cached::CompareNEValueNumber#1aeec1bd ON FIRST 1 OUTPUT Lhs.1, Lhs.0, Lhs.2, Lhs.3, Lhs.4, Lhs.5

             20   ~0%    {6} r14 = JOIN r12 WITH project#IRGuards::Cached::CompareEQValueNumber#994b6833 ON FIRST 1 OUTPUT Lhs.5, Lhs.0, Lhs.1, Lhs.2, Lhs.3, Lhs.4
             20   ~0%    {6}    | JOIN WITH `IRGuards::AbstractValue.getDualValue/0#dispred#bfb2631d` ON FIRST 1 OUTPUT Lhs.2, Lhs.1, Lhs.3, Lhs.4, Lhs.5, Rhs.1

             70   ~0%    {6} r15 = r13 UNION r14
             70   ~1%    {7}    | JOIN WITH `Operand::Operand.getDef/0#dispred#a70e8079` ON FIRST 1 OUTPUT Rhs.1, _, Lhs.1, Lhs.2, Lhs.3, Lhs.4, Lhs.5
             70   ~0%    {7}    | REWRITE WITH Out.1 := 0
             66   ~2%    {5}    | JOIN WITH `IRGuards::Cached::int_value/1#f9d7a458` ON FIRST 2 OUTPUT Lhs.2, Lhs.3, Lhs.4, Lhs.5, Lhs.6

              0   ~0%    {5} r16 = JOIN r1 WITH `IRGuards::Cached::BuiltinExpectCallValueNumber.getAUse/0#dispred#23233591` ON FIRST 1 OUTPUT Rhs.1, Lhs.1, Lhs.2, Lhs.3, Lhs.4
              0   ~0%    {6}    | JOIN WITH `IRGuards::Cached::CompareValueNumber.hasOperands/2#dispred#7aa36763_102#join_rhs` ON FIRST 1 OUTPUT Rhs.1, Lhs.1, Lhs.2, Lhs.3, Lhs.4, Rhs.2

              0   ~0%    {6} r17 = JOIN r16 WITH project#IRGuards::Cached::CompareNEValueNumber#1aeec1bd ON FIRST 1 OUTPUT Lhs.5, Lhs.1, Lhs.2, Lhs.3, Lhs.0, Lhs.4

              0   ~0%    {6} r18 = JOIN r16 WITH project#IRGuards::Cached::CompareEQValueNumber#994b6833 ON FIRST 1 OUTPUT Lhs.4, Lhs.1, Lhs.2, Lhs.3, Lhs.0, Lhs.5
              0   ~0%    {6}    | JOIN WITH `IRGuards::AbstractValue.getDualValue/0#dispred#bfb2631d_10#join_rhs` ON FIRST 1 OUTPUT Lhs.5, Lhs.1, Lhs.2, Lhs.3, Lhs.4, Rhs.1

              0   ~0%    {6} r19 = r17 UNION r18
              0   ~0%    {7}    | JOIN WITH `Operand::Operand.getAnyDef/0#dispred#8dbe2fb8` ON FIRST 1 OUTPUT Rhs.1, _, Lhs.1, Lhs.2, Lhs.3, Lhs.4, Lhs.5
              0   ~0%    {7}    | REWRITE WITH Out.1 := 0
              0   ~0%    {5}    | JOIN WITH `IRGuards::Cached::int_value/1#f9d7a458` ON FIRST 2 OUTPUT Lhs.5, Lhs.2, Lhs.3, Lhs.4, Lhs.6

           4052   ~1%    {5} r20 = r1 UNION r2 UNION r4 UNION r5 UNION r7 UNION r8 UNION r10 UNION r11 UNION r15 UNION r19
           4020   ~1%    {5}    | AND NOT `IRGuards::Cached::unary_compares_eq/5#7aa979d8#prev`(FIRST 5)
                         return r20
```
2025-01-22 14:54:24 +01:00
Mathias Vorreiter Pedersen
a1449bf0bd C++: Accept test changes. 2025-01-21 20:43:54 +00:00
Mathias Vorreiter Pedersen
12666848c0 C++: Fix conflation in 'Pure' models. 2025-01-21 20:43:53 +00:00
Mathias Vorreiter Pedersen
503f018600 C++: Add taint test with false flow from conflation. 2025-01-21 20:43:52 +00:00
Jeroen Ketema
442dad4ff9 C++: Update PreprocBlock.qll QLDoc and add C++23 test 2025-01-21 18:02:28 +01:00
Jeroen Ketema
ac18e7494f C++: Update stats file 2025-01-21 16:14:29 +01:00
Jeroen Ketema
32ff8dc0f6 C++: Add upgrade and downgrade scripts 2025-01-21 16:14:27 +01:00
Jeroen Ketema
e0acf262d5 C++: Add change note 2025-01-21 16:14:18 +01:00
Jeroen Ketema
9fd95381dc C++: Support #elifdef #elifndef, and MSVC's #import 2025-01-21 16:14:16 +01:00
Jeroen Ketema
a0ef2888c7 C++: Add more preprocessor tests 2025-01-21 16:14:13 +01:00
github-actions[bot]
ebe9088458 Post-release preparation for codeql-cli-2.20.2 2025-01-21 13:58:45 +00:00
Chris Smowton
9fa1ad9d8d Fix changelog typos 2025-01-21 13:58:44 +00:00
github-actions[bot]
f21784db9d Release preparation for version 2.20.2 2025-01-21 13:58:43 +00:00
Chris Smowton
fb140404b6 Revert "Release preparation for version 2.20.2" 2025-01-21 13:58:38 +00:00
github-actions[bot]
fbb7f0a0c6 Post-release preparation for codeql-cli-2.20.2 2025-01-20 21:11:14 +00:00
github-actions[bot]
a0512a50f2 Release preparation for version 2.20.2 2025-01-20 21:11:12 +00:00
Mathias Vorreiter Pedersen
ed651294b6 Merge branch 'main' into remove-conflation-from-out-nodes 2025-01-20 12:42:26 +00:00
Jeroen Ketema
1b2d7bcbfa Merge pull request #18534 from jketema/uncomment
C++: Uncomment more preprocessor tests
2025-01-20 12:59:20 +01:00
Jeroen Ketema
4b85ea3bc6 Merge pull request #18502 from jketema/consteval
C++: Support `if consteval` and `if ! consteval`
2025-01-20 12:49:02 +01:00