@@ -211,10 +211,17 @@ private predicate fieldStoreStepNoChi(Node node1, FieldContent f, PostUpdateNode
211211 )
212212}
213213
214+ private FieldAddressInstruction getFieldInstruction ( Instruction instr ) {
215+ result = instr or
216+ result = instr .( CopyValueInstruction ) .getUnary ( )
217+ }
218+
214219pragma [ noinline]
215- private predicate getWrittenField ( StoreInstruction store , Field f , Class c ) {
220+ private predicate getWrittenField ( Instruction instr , Field f , Class c ) {
216221 exists ( FieldAddressInstruction fa |
217- fa = store .getDestinationAddress ( ) and
222+ fa =
223+ getFieldInstruction ( [ any ( StoreInstruction store | instr = store ) .getDestinationAddress ( ) ,
224+ any ( WriteSideEffectInstruction write | instr = write ) .getDestinationAddress ( ) ] ) and
218225 f = fa .getField ( ) and
219226 c = f .getDeclaringType ( )
220227 )
@@ -265,7 +272,23 @@ private predicate arrayStoreStepChi(Node node1, ArrayContent a, PostUpdateNode n
265272predicate storeStep ( Node node1 , Content f , PostUpdateNode node2 ) {
266273 fieldStoreStepNoChi ( node1 , f , node2 ) or
267274 fieldStoreStepChi ( node1 , f , node2 ) or
268- arrayStoreStepChi ( node1 , f , node2 )
275+ arrayStoreStepChi ( node1 , f , node2 ) or
276+ fieldStoreStepAfterArraySuppression ( node1 , f , node2 )
277+ }
278+
279+ // This predicate pushes the correct `FieldContent` onto the access path when the
280+ // `suppressArrayRead` predicate has popped off an `ArrayContent`.
281+ private predicate fieldStoreStepAfterArraySuppression (
282+ Node node1 , FieldContent f , PostUpdateNode node2
283+ ) {
284+ exists ( BufferMayWriteSideEffectInstruction write , ChiInstruction chi , Class c |
285+ not chi .isResultConflated ( ) and
286+ node1 .asInstruction ( ) = chi and
287+ node2 .asInstruction ( ) = chi and
288+ chi .getPartial ( ) = write and
289+ getWrittenField ( write , f .getAField ( ) , c ) and
290+ f .hasOffset ( c , _, _)
291+ )
269292}
270293
271294bindingset [ result , i]
@@ -302,11 +325,53 @@ private predicate fieldReadStep(Node node1, FieldContent f, Node node2) {
302325 )
303326}
304327
328+ predicate suppressArrayRead ( Node node1 , ArrayContent a , Node node2 ) {
329+ a = TArrayContent ( ) and
330+ exists ( BufferMayWriteSideEffectInstruction write , ChiInstruction chi |
331+ node1 .asInstruction ( ) = write and
332+ node2 .asInstruction ( ) = chi and
333+ chi .getPartial ( ) = write and
334+ getWrittenField ( write , _, _)
335+ )
336+ }
337+
338+ private class ArrayToPointerConvertInstruction extends ConvertInstruction {
339+ ArrayToPointerConvertInstruction ( ) {
340+ this .getUnary ( ) .getResultType ( ) instanceof ArrayType and
341+ this .getResultType ( ) instanceof PointerType
342+ }
343+ }
344+
305345private predicate arrayReadStep ( Node node1 , ArrayContent a , Node node2 ) {
306346 a = TArrayContent ( ) and
307- exists ( LoadInstruction load |
308- node1 .asInstruction ( ) = load .getSourceValueOperand ( ) .getAnyDef ( ) and
309- load = node2 .asInstruction ( )
347+ (
348+ // In cases such as:
349+ // ```cpp
350+ // void f(int* pa) {
351+ // *pa = source();
352+ // }
353+ // ...
354+ // int x;
355+ // f(&x);
356+ // use(x);
357+ // ```
358+ // the load on `x` in `use(x)` will exactly overlap with its definition (in this case the definition
359+ // is a `BufferMayWriteSideEffect`).
360+ exists ( LoadInstruction load |
361+ node1 .asInstruction ( ) = load .getSourceValue ( ) and
362+ load = node2 .asInstruction ( )
363+ )
364+ or
365+ // Explicit dereferences such as `*p` or `p[i]` where `p` is a pointer or array.
366+ exists ( LoadInstruction load |
367+ node1 .asInstruction ( ) = load .getSourceValueOperand ( ) .getAnyDef ( ) and
368+ load = node2 .asInstruction ( ) and
369+ (
370+ load .getSourceAddress ( ) instanceof LoadInstruction or
371+ load .getSourceAddress ( ) instanceof ArrayToPointerConvertInstruction or
372+ load .getSourceAddress ( ) instanceof PointerAddInstruction
373+ )
374+ )
310375 )
311376}
312377
@@ -317,7 +382,19 @@ private predicate arrayReadStep(Node node1, ArrayContent a, Node node2) {
317382 */
318383predicate readStep ( Node node1 , Content f , Node node2 ) {
319384 fieldReadStep ( node1 , f , node2 ) or
320- arrayReadStep ( node1 , f , node2 )
385+ arrayReadStep ( node1 , f , node2 ) or
386+ // When a store step happens in a function that looks like an array write such as:
387+ // ```cpp
388+ // void f(int* pa) {
389+ // *pa = source();
390+ // }
391+ // ```
392+ // it can be a write to an array, but it can also happen that `f` is called as `f(&a.x)`. If that is
393+ // the case, the `ArrayContent` that was written by the call to `f` should be popped off the access
394+ // path, and a `FieldContent` containing `x` should be pushed instead.
395+ // So this case pops `ArrayContent` off the access path, and the `fieldStoreStepAfterArraySuppression`
396+ // predicate in `storeStep` ensures that we push the right `FieldContent` onto the access path.
397+ suppressArrayRead ( node1 , f , node2 )
321398}
322399
323400/**
0 commit comments