Skip to content

Commit a58aecf

Browse files
committed
C++: Fix reference-related duplication by checking if any expression in the convertion chain is a glvalue expression.
1 parent 7f4a863 commit a58aecf

2 files changed

Lines changed: 18 additions & 8 deletions

File tree

‎cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/ExprNodes.qll‎

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,16 @@ private module Cached {
244244
)
245245
}
246246

247+
/**
248+
* Gets a `glvalue` expression whose unconverted result is the same as the
249+
* unconverted result of `e`.
250+
*/
251+
pragma[inline]
252+
private Expr getAGLValueCategoryExpr(Expr e) {
253+
result.isGLValueCategory() and
254+
result.getUnconverted() = e.getUnconverted()
255+
}
256+
247257
/** Holds if `node` should be an `IndirectOperand` that maps `node.asExpr()` to `e`. */
248258
private predicate exprNodeShouldBeIndirectOperand(IndirectOperand node, Expr e, int n) {
249259
exists(ArgumentOperand operand | isIndirectOperandOfArgument(node, operand, e, n) |
@@ -262,13 +272,13 @@ private module Cached {
262272
// The qualifier is associated with both `*x` and the lvalue-to-rvalue
263273
// conversion of `x`. Only `*x` is a glvalue and should map to the
264274
// indirect qualifier node; the converted `x` is a pointer prvalue and
265-
// should map to the direct qualifier node. Restricting `e` to only be
266-
// expressions for which `e.isGLValueCategory()` holds ensures that `*x`
267-
// is the result of calling `asExpr()` while `asIndirectExpr()` gives
268-
// `x`.
275+
// should map to the direct qualifier node. So we require that the fully
276+
// converted qualifier (i.e., the expression with `n = 0`) is a glvalue,
277+
// and then map every expression in the conversion chain with the same
278+
// unconverted expression to the indirect node.
269279
operand.isGLValue() and
270280
operand instanceof ThisArgumentOperand and
271-
e.isGLValueCategory()
281+
isIndirectOperandOfArgument(node, operand, getAGLValueCategoryExpr(e), 0)
272282
or
273283
// When an argument (qualifier or positional) is a prvalue and the
274284
// parameter (qualifier or positional) is a (const) reference, IR

‎cpp/ql/test/library-tests/dataflow/asExpr/test.cpp‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,18 +64,18 @@ struct Derived : Foo {};
6464

6565
void test_qualifiers(Foo x, Foo &r, Foo *p, Foo *&rp, Derived d, Derived &rd) {
6666
x.f(); // $ asExpr=x asIndirectExpr=x
67-
r.f(); // $ asExpr=r asIndirectExpr=r numberOfNodes="r: 2"
67+
r.f(); // $ asExpr=r asIndirectExpr=r
6868
p->f(); // $ asExpr=p asIndirectExpr=p
6969
(*p).f(); // $ asExpr="* ..." asIndirectExpr="* ..." asExpr="p(* ...)" asIndirectExpr="p(* ...)"
7070
rp->f(); // $ asExpr=rp asIndirectExpr=rp numberOfIndirectNodes="rp: 2" numberOfNodes="rp: 2"
7171
(*rp).f(); // $ asExpr="* ..." asIndirectExpr="* ..." asExpr="rp(* ...)" asIndirectExpr="rp(* ...)" asIndirectExpr=rp numberOfIndirectNodes="rp: 2"
7272
d.f(); // $ asExpr=d asIndirectExpr=d
73-
rd.f(); // $ asExpr=rd asIndirectExpr=rd numberOfNodes="rd: 2"
73+
rd.f(); // $ asExpr=rd asIndirectExpr=rd
7474
}
7575

7676
void test_inner_glvalue_qualifiers(Foo x, Foo &r) {
7777
Foo arr[2];
7878
(*&x).f(); // $ asExpr="* ..." asIndirectExpr="* ..." asExpr="& ...(* ...)" asIndirectExpr="& ...(* ...)" asExpr="x(* ...)" asIndirectExpr="x(* ...)"
79-
(*&r).f(); // $ asExpr="* ..." asIndirectExpr="* ..." asExpr="& ...(* ...)" asIndirectExpr="& ...(* ...)" asExpr="r(* ...)" asIndirectExpr="r(* ...)" numberOfNodes="r: 2"
79+
(*&r).f(); // $ asExpr="* ..." asIndirectExpr="* ..." asExpr="& ...(* ...)" asIndirectExpr="& ...(* ...)" asExpr="r(* ...)" asIndirectExpr="r(* ...)"
8080
(*arr).f(); // $ asExpr="* ..." asIndirectExpr="* ..." asExpr="arr(* ...)" asIndirectExpr="arr(* ...)"
8181
}

0 commit comments

Comments
 (0)