diff --git a/cpp/ql/lib/semmle/code/cpp/PrintAST.qll b/cpp/ql/lib/semmle/code/cpp/PrintAST.qll index cc5a8d6c3355..7a6307898ef5 100644 --- a/cpp/ql/lib/semmle/code/cpp/PrintAST.qll +++ b/cpp/ql/lib/semmle/code/cpp/PrintAST.qll @@ -954,9 +954,18 @@ private predicate namedExprChildPredicates(Expr expr, Element ele, string pred) expr.(C11GenericExpr).getAssociationExpr(n) = ele and pred = "getAssociationExpr(" + n + ")" ) or - expr.(Call).getQualifier() = ele and pred = "getQualifier()" - or - exists(int n | expr.(Call).getArgument(n) = ele and pred = "getArgument(" + n.toString() + ")") + // OverloadedArrayExpr::getArrayBase/0 also considers qualifiers, and is already handled below. + not expr.(OverloadedArrayExpr).getArrayBase() = expr.(Call).getQualifier() and + expr.(Call).getQualifier() = ele and + pred = "getQualifier()" + or + // OverloadedArrayExpr::getArrayBase/0 and OverloadedArrayExpr::getArrayOffset/0 also consider arguments, and are already handled below. + exists(int n, Expr arg | expr.(Call).getArgument(n) = arg | + not expr.(OverloadedArrayExpr).getArrayBase() = arg and + not expr.(OverloadedArrayExpr).getArrayOffset() = arg and + arg = ele and + pred = "getArgument(" + n.toString() + ")" + ) or expr.(ExprCall).getExpr() = ele and pred = "getExpr()" or @@ -964,7 +973,7 @@ private predicate namedExprChildPredicates(Expr expr, Element ele, string pred) or expr.(OverloadedArrayExpr).getArrayOffset() = ele and pred = "getArrayOffset()" or - // OverloadedPointerDereferenceExpr::getExpr/0 also considers qualifiers, which are already handled above for all Call classes. + // OverloadedPointerDereferenceExpr::getExpr/0 also considers qualifiers, and is already handled above for all Call classes. not expr.(OverloadedPointerDereferenceExpr).getQualifier() = expr.(OverloadedPointerDereferenceExpr).getExpr() and expr.(OverloadedPointerDereferenceExpr).getExpr() = ele and diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/PrintIR.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/PrintIR.qll index 7fd66ba84414..41e1a4c3082d 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/PrintIR.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/PrintIR.qll @@ -422,16 +422,22 @@ private int getSuccessorIndex(IRBlock pred, IRBlock succ) { * has the given `value`. */ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, string value) { - exists(EdgeKind kind, IRBlock predBlock, IRBlock succBlock | + exists(IRBlock predBlock, IRBlock succBlock | predBlock = pred.getBlock() and succBlock = succ.getBlock() and - predBlock.getSuccessor(kind) = succBlock and ( - ( - key = "semmle.label" and - if predBlock.getBackEdgeSuccessor(kind) = succBlock - then value = kind.toString() + " (back edge)" - else value = kind.toString() + key = "semmle.label" and + exists(string kinds | + kinds = + strictconcat(EdgeKind k | + predBlock.getSuccessor(k) = succBlock + | + k.toString(), "|" order by k.toString() + ) + | + if predBlock.getBackEdgeSuccessor(_) = succBlock + then value = kinds + " (back edge)" + else value = kinds ) or key = "semmle.order" and diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/PrintIR.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/PrintIR.qll index 7fd66ba84414..41e1a4c3082d 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/PrintIR.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/PrintIR.qll @@ -422,16 +422,22 @@ private int getSuccessorIndex(IRBlock pred, IRBlock succ) { * has the given `value`. */ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, string value) { - exists(EdgeKind kind, IRBlock predBlock, IRBlock succBlock | + exists(IRBlock predBlock, IRBlock succBlock | predBlock = pred.getBlock() and succBlock = succ.getBlock() and - predBlock.getSuccessor(kind) = succBlock and ( - ( - key = "semmle.label" and - if predBlock.getBackEdgeSuccessor(kind) = succBlock - then value = kind.toString() + " (back edge)" - else value = kind.toString() + key = "semmle.label" and + exists(string kinds | + kinds = + strictconcat(EdgeKind k | + predBlock.getSuccessor(k) = succBlock + | + k.toString(), "|" order by k.toString() + ) + | + if predBlock.getBackEdgeSuccessor(_) = succBlock + then value = kinds + " (back edge)" + else value = kinds ) or key = "semmle.order" and diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/PrintIR.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/PrintIR.qll index 7fd66ba84414..41e1a4c3082d 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/PrintIR.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/PrintIR.qll @@ -422,16 +422,22 @@ private int getSuccessorIndex(IRBlock pred, IRBlock succ) { * has the given `value`. */ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, string value) { - exists(EdgeKind kind, IRBlock predBlock, IRBlock succBlock | + exists(IRBlock predBlock, IRBlock succBlock | predBlock = pred.getBlock() and succBlock = succ.getBlock() and - predBlock.getSuccessor(kind) = succBlock and ( - ( - key = "semmle.label" and - if predBlock.getBackEdgeSuccessor(kind) = succBlock - then value = kind.toString() + " (back edge)" - else value = kind.toString() + key = "semmle.label" and + exists(string kinds | + kinds = + strictconcat(EdgeKind k | + predBlock.getSuccessor(k) = succBlock + | + k.toString(), "|" order by k.toString() + ) + | + if predBlock.getBackEdgeSuccessor(_) = succBlock + then value = kinds + " (back edge)" + else value = kinds ) or key = "semmle.order" and diff --git a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected index d4f9c4f96c61..ea242065ac17 100644 --- a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected +++ b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected @@ -24086,6 +24086,38 @@ ir.cpp: # 2717| ValueCategory = prvalue # 2717| getThen(): [BlockStmt] { ... } # 2718| getStmt(16): [ReturnStmt] return ... +# 2720| [CopyAssignmentOperator] WithBracketOperator& WithBracketOperator::operator=(WithBracketOperator const&) +# 2720| : +#-----| getParameter(0): [Parameter] (unnamed parameter 0) +#-----| Type = [LValueReferenceType] const WithBracketOperator & +# 2720| [MoveAssignmentOperator] WithBracketOperator& WithBracketOperator::operator=(WithBracketOperator&&) +# 2720| : +#-----| getParameter(0): [Parameter] (unnamed parameter 0) +#-----| Type = [RValueReferenceType] WithBracketOperator && +# 2721| [ConstMemberFunction] char const& WithBracketOperator::operator[](int) const +# 2721| : +# 2721| getParameter(0): [Parameter] pos +# 2721| Type = [IntType] int +# 2724| [TopLevelFunction] char UseBracketOperator(WithBracketOperator const, int) +# 2724| : +# 2724| getParameter(0): [Parameter] x +# 2724| Type = [SpecifiedType] const WithBracketOperator +# 2724| getParameter(1): [Parameter] i +# 2724| Type = [IntType] int +# 2724| getEntryPoint(): [BlockStmt] { ... } +# 2725| getStmt(0): [ReturnStmt] return ... +# 2725| getExpr(): [OverloadedArrayExpr] call to operator[] +# 2725| Type = [LValueReferenceType] const char & +# 2725| ValueCategory = prvalue +# 2725| getArrayBase(): [VariableAccess] x +# 2725| Type = [SpecifiedType] const WithBracketOperator +# 2725| ValueCategory = lvalue +# 2725| getArrayOffset(): [VariableAccess] i +# 2725| Type = [IntType] int +# 2725| ValueCategory = prvalue(load) +# 2725| getExpr().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference) +# 2725| Type = [PlainCharType] char +# 2725| ValueCategory = prvalue(load) many-defs-per-use.cpp: # 34| [TopLevelFunction] void many_defs_per_use() # 34| : diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected index 224ac9a0ed9b..4f340042cb9a 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected @@ -19713,6 +19713,33 @@ ir.cpp: # 2698| v2698_10(void) = AliasedUse : m2698_3 # 2698| v2698_11(void) = ExitFunction : +# 2724| char UseBracketOperator(WithBracketOperator const, int) +# 2724| Block 0 +# 2724| v2724_1(void) = EnterFunction : +# 2724| m2724_2(unknown) = AliasedDefinition : +# 2724| m2724_3(unknown) = InitializeNonLocal : +# 2724| m2724_4(unknown) = Chi : total:m2724_2, partial:m2724_3 +# 2724| r2724_5(glval) = VariableAddress[x] : +# 2724| m2724_6(WithBracketOperator) = InitializeParameter[x] : &:r2724_5 +# 2724| m2724_7(unknown) = Chi : total:m2724_4, partial:m2724_6 +# 2724| r2724_8(glval) = VariableAddress[i] : +# 2724| m2724_9(int) = InitializeParameter[i] : &:r2724_8 +# 2725| r2725_1(glval) = VariableAddress[#return] : +# 2725| r2725_2(glval) = VariableAddress[x] : +# 2725| r2725_3(glval) = FunctionAddress[operator[]] : +# 2725| r2725_4(glval) = VariableAddress[i] : +# 2725| r2725_5(int) = Load[i] : &:r2725_4, m2724_9 +# 2725| r2725_6(char &) = Call[operator[]] : func:r2725_3, this:r2725_2, 0:r2725_5 +# 2725| m2725_7(unknown) = ^CallSideEffect : ~m2724_7 +# 2725| m2725_8(unknown) = Chi : total:m2724_7, partial:m2725_7 +# 2725| v2725_9(void) = ^IndirectReadSideEffect[-1] : &:r2725_2, ~m2725_8 +# 2725| r2725_10(char) = Load[?] : &:r2725_6, ~m2725_8 +# 2725| m2725_11(char) = Store[#return] : &:r2725_1, r2725_10 +# 2724| r2724_10(glval) = VariableAddress[#return] : +# 2724| v2724_11(void) = ReturnValue : &:r2724_10, m2725_11 +# 2724| v2724_12(void) = AliasedUse : ~m2725_8 +# 2724| v2724_13(void) = ExitFunction : + many-defs-per-use.cpp: # 34| void many_defs_per_use() # 34| Block 0 diff --git a/cpp/ql/test/library-tests/ir/ir/ir.cpp b/cpp/ql/test/library-tests/ir/ir/ir.cpp index bb4698ea7e23..67db690dc54b 100644 --- a/cpp/ql/test/library-tests/ir/ir/ir.cpp +++ b/cpp/ql/test/library-tests/ir/ir/ir.cpp @@ -2717,4 +2717,12 @@ void branch_on_integral_in_cpp(int x1, int x2) { if(!x_1_and_2) {} } +struct WithBracketOperator { + const char& operator[](int pos) const; +}; + +char UseBracketOperator(const WithBracketOperator x, int i) { + return x[i]; +} + // semmle-extractor-options: -std=c++20 --clang diff --git a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected index 8600049dd225..31faa22d9fcd 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -18031,6 +18031,30 @@ ir.cpp: # 2698| v2698_9(void) = AliasedUse : ~m? # 2698| v2698_10(void) = ExitFunction : +# 2724| char UseBracketOperator(WithBracketOperator const, int) +# 2724| Block 0 +# 2724| v2724_1(void) = EnterFunction : +# 2724| mu2724_2(unknown) = AliasedDefinition : +# 2724| mu2724_3(unknown) = InitializeNonLocal : +# 2724| r2724_4(glval) = VariableAddress[x] : +# 2724| mu2724_5(WithBracketOperator) = InitializeParameter[x] : &:r2724_4 +# 2724| r2724_6(glval) = VariableAddress[i] : +# 2724| mu2724_7(int) = InitializeParameter[i] : &:r2724_6 +# 2725| r2725_1(glval) = VariableAddress[#return] : +# 2725| r2725_2(glval) = VariableAddress[x] : +# 2725| r2725_3(glval) = FunctionAddress[operator[]] : +# 2725| r2725_4(glval) = VariableAddress[i] : +# 2725| r2725_5(int) = Load[i] : &:r2725_4, ~m? +# 2725| r2725_6(char &) = Call[operator[]] : func:r2725_3, this:r2725_2, 0:r2725_5 +# 2725| mu2725_7(unknown) = ^CallSideEffect : ~m? +# 2725| v2725_8(void) = ^IndirectReadSideEffect[-1] : &:r2725_2, ~m? +# 2725| r2725_9(char) = Load[?] : &:r2725_6, ~m? +# 2725| mu2725_10(char) = Store[#return] : &:r2725_1, r2725_9 +# 2724| r2724_8(glval) = VariableAddress[#return] : +# 2724| v2724_9(void) = ReturnValue : &:r2724_8, ~m? +# 2724| v2724_10(void) = AliasedUse : ~m? +# 2724| v2724_11(void) = ExitFunction : + many-defs-per-use.cpp: # 34| void many_defs_per_use() # 34| Block 0