@@ -29,7 +29,7 @@ private predicate stdIdentityFunction(Function f) { f.hasQualifiedName("std", ["
2929 */
3030private predicate stdAddressOf ( Function f ) { f .hasQualifiedName ( "std" , "addressof" ) }
3131
32- private predicate lvalueToLvalueStep ( Expr lvalueIn , Expr lvalueOut ) {
32+ private predicate lvalueToLvalueStepPure ( Expr lvalueIn , Expr lvalueOut ) {
3333 lvalueIn .getConversion ( ) = lvalueOut .( ParenthesisExpr )
3434 or
3535 // When an object is implicitly converted to a reference to one of its base
@@ -42,6 +42,10 @@ private predicate lvalueToLvalueStep(Expr lvalueIn, Expr lvalueOut) {
4242 // such casts.
4343 lvalueIn .getConversion ( ) = lvalueOut and
4444 lvalueOut .( CStyleCast ) .isImplicit ( )
45+ }
46+
47+ private predicate lvalueToLvalueStep ( Expr lvalueIn , Expr lvalueOut ) {
48+ lvalueToLvalueStepPure ( lvalueIn , lvalueOut )
4549 or
4650 // C++ only
4751 lvalueIn = lvalueOut .( PrefixCrementOperation ) .getOperand ( ) .getFullyConverted ( )
@@ -214,6 +218,69 @@ private predicate referenceToUpdate(Expr reference, Expr outer, ControlFlowNode
214218 )
215219}
216220
221+ private predicate lvalueFromVariableAccess ( VariableAccess va , Expr lvalue ) {
222+ // Base case for non-reference types.
223+ lvalue = va and
224+ not va .getConversion ( ) instanceof ReferenceDereferenceExpr
225+ or
226+ // Base case for reference types where we pretend that they are
227+ // non-reference types. The type of the target of `va` can be `ReferenceType`
228+ // or `FunctionReferenceType`.
229+ lvalue = va .getConversion ( ) .( ReferenceDereferenceExpr )
230+ or
231+ // lvalue -> lvalue
232+ exists ( Expr prev |
233+ lvalueFromVariableAccess ( va , prev ) and
234+ lvalueToLvalueStep ( prev , lvalue )
235+ )
236+ or
237+ // pointer -> lvalue
238+ exists ( Expr prev |
239+ pointerFromVariableAccess ( va , prev ) and
240+ pointerToLvalueStep ( prev , lvalue )
241+ )
242+ or
243+ // reference -> lvalue
244+ exists ( Expr prev |
245+ referenceFromVariableAccess ( va , prev ) and
246+ referenceToLvalueStep ( prev , lvalue )
247+ )
248+ }
249+
250+ private predicate pointerFromVariableAccess ( VariableAccess va , Expr pointer ) {
251+ // pointer -> pointer
252+ exists ( Expr prev |
253+ pointerFromVariableAccess ( va , prev ) and
254+ pointerToPointerStep ( prev , pointer )
255+ )
256+ or
257+ // reference -> pointer
258+ exists ( Expr prev |
259+ referenceFromVariableAccess ( va , prev ) and
260+ referenceToPointerStep ( prev , pointer )
261+ )
262+ or
263+ // lvalue -> pointer
264+ exists ( Expr prev |
265+ lvalueFromVariableAccess ( va , prev ) and
266+ lvalueToPointerStep ( prev , pointer )
267+ )
268+ }
269+
270+ private predicate referenceFromVariableAccess ( VariableAccess va , Expr reference ) {
271+ // reference -> reference
272+ exists ( Expr prev |
273+ referenceFromVariableAccess ( va , prev ) and
274+ referenceToReferenceStep ( prev , reference )
275+ )
276+ or
277+ // lvalue -> reference
278+ exists ( Expr prev |
279+ lvalueFromVariableAccess ( va , prev ) and
280+ lvalueToReferenceStep ( prev , reference )
281+ )
282+ }
283+
217284/**
218285 * Holds if `node` is a control-flow node that may modify `inner` (or what it
219286 * points to) through `outer`. The two expressions may be `Conversion`s. Plain
@@ -236,7 +303,7 @@ predicate valueToUpdate(Expr inner, Expr outer, ControlFlowNode node) {
236303 (
237304 inner instanceof VariableAccess and
238305 // Don't track non-field assignments
239- ( assignmentTo ( outer , _) implies inner instanceof FieldAccess )
306+ not ( assignmentTo ( outer , _) and outer . ( VariableAccess ) . getTarget ( ) instanceof StackVariable )
240307 or
241308 inner instanceof ThisExpr
242309 or
@@ -245,3 +312,27 @@ predicate valueToUpdate(Expr inner, Expr outer, ControlFlowNode node) {
245312 // can't do anything useful with those at the moment.
246313 )
247314}
315+
316+ /**
317+ * Holds if `e` is a fully-converted expression that evaluates to an lvalue
318+ * derived from `va` and is used for reading from or assigning to. This is in
319+ * contrast with a variable access that is used for taking an address (`&x`)
320+ * or simply discarding its value (`x;`).
321+ *
322+ * This analysis does not propagate across assignments or calls, and unlike
323+ * `variableAccessedAsValue` in `semmle.code.cpp.dataflow.EscapesTree` it
324+ * propagates through array accesses but not field accesses. The analysis is
325+ * also not concerned with whether the lvalue `e` is converted to an rvalue --
326+ * to examine that, use the relevant member predicates on `Expr`.
327+ *
328+ * If `va` has reference type, the analysis concerns the value pointed to by
329+ * the reference rather than the reference itself. The expression `e` may be a
330+ * `Conversion`.
331+ */
332+ predicate variablePartiallyAccessed ( VariableAccess va , Expr e ) {
333+ lvalueFromVariableAccess ( va , e ) and
334+ not lvalueToLvalueStepPure ( e , _) and
335+ not lvalueToPointerStep ( e , _) and
336+ not lvalueToReferenceStep ( e , _) and
337+ not e = any ( ExprInVoidContext eivc | e = eivc .getConversion * ( ) )
338+ }
0 commit comments