@@ -228,69 +228,86 @@ private class ArrayContent extends Content, TArrayContent {
228228 override string toString ( ) { result = "array content" }
229229}
230230
231- private predicate fieldStoreStepNoChi ( Node node1 , FieldContent f , PostUpdateNode node2 ) {
232- exists ( StoreInstruction store , Class c |
233- store = node2 .asInstruction ( ) and
231+ /**
232+ * A store step from the value of a `StoreInstruction` to the "innermost" field of the destination.
233+ * This predicate only holds when there is no `ChiInsturction` that merges the result of the
234+ * `StoreInstruction` into a larger memory.
235+ */
236+ private predicate instrToFieldNodeStoreStepNoChi (
237+ Node node1 , FieldContent f , PartialDefinitionNode node2
238+ ) {
239+ exists ( StoreInstruction store , PostUpdateFieldNode post |
240+ post = node2 .getPartialDefinition ( ) and
241+ not exists ( ChiInstruction chi | chi .getPartial ( ) = store ) and
242+ post .getPreUpdateNode ( ) = getFieldNodeForFieldInstruction ( store .getDestinationAddress ( ) ) and
234243 store .getSourceValueOperand ( ) = node1 .asOperand ( ) and
235- getWrittenField ( store , f .( FieldContent ) .getAField ( ) , c ) and
236- f .hasOffset ( c , _, _)
244+ f .getADirectField ( ) = post .getField ( )
237245 )
238246}
239247
240- private FieldAddressInstruction getFieldInstruction ( Instruction instr ) {
241- result = instr or
242- result = instr .( CopyValueInstruction ) .getUnary ( )
243- }
244-
245- pragma [ noinline]
246- private predicate getWrittenField ( Instruction instr , Field f , Class c ) {
247- exists ( FieldAddressInstruction fa |
248- fa =
249- getFieldInstruction ( [
250- instr .( StoreInstruction ) .getDestinationAddress ( ) ,
251- instr .( WriteSideEffectInstruction ) .getDestinationAddress ( )
252- ] ) and
253- f = fa .getField ( ) and
254- c = f .getDeclaringType ( )
248+ /**
249+ * A store step from a `StoreInstruction` to the "innermost" field
250+ * of the destination. This predicate only holds when there exists a `ChiInstruction` that merges the
251+ * result of the `StoreInstruction` into a larger memory.
252+ */
253+ private predicate instrToFieldNodeStoreStepChi (
254+ Node node1 , FieldContent f , PartialDefinitionNode node2
255+ ) {
256+ exists (
257+ ChiPartialOperand operand , StoreInstruction store , ChiInstruction chi , PostUpdateFieldNode post
258+ |
259+ post = node2 .getPartialDefinition ( ) and
260+ not chi .isResultConflated ( ) and
261+ node1 .asOperand ( ) = operand and
262+ chi .getPartialOperand ( ) = operand and
263+ store = operand .getDef ( ) and
264+ post .getPreUpdateNode ( ) = getFieldNodeForFieldInstruction ( store .getDestinationAddress ( ) ) and
265+ f .getADirectField ( ) = post .getField ( )
255266 )
256267}
257268
258- private predicate fieldStoreStepChi ( Node node1 , FieldContent f , PostUpdateNode node2 ) {
259- exists ( ChiPartialOperand operand , ChiInstruction chi |
260- chi . getPartialOperand ( ) = operand and
261- node1 . asOperand ( ) = operand and
262- node2 . asInstruction ( ) = chi and
263- exists ( Class c |
264- c = chi . getResultType ( ) and
265- exists ( int startBit , int endBit |
266- chi .getUpdatedInterval ( startBit , endBit ) and
267- f . hasOffset ( c , startBit , endBit )
268- )
269- or
270- getWrittenField ( operand . getDef ( ) , f . getAField ( ) , c ) and
271- f . hasOffset ( c , _ , _ )
272- )
269+ private predicate callableWithoutDefinitionStoreStep (
270+ Node node1 , FieldContent f , PartialDefinitionNode node2
271+ ) {
272+ exists (
273+ WriteSideEffectInstruction write , ChiInstruction chi , PostUpdateFieldNode post ,
274+ Function callable
275+ |
276+ chi . getPartial ( ) = write and
277+ not chi .isResultConflated ( ) and
278+ post = node2 . getPartialDefinition ( ) and
279+ node1 . asInstruction ( ) = write and
280+ post . getPreUpdateNode ( ) = getFieldNodeForFieldInstruction ( write . getDestinationAddress ( ) ) and
281+ f . getADirectField ( ) = post . getField ( ) and
282+ callable = write . getPrimaryInstruction ( ) . ( CallInstruction ) . getStaticCallTarget ( ) and
283+ not callable . hasDefinition ( )
273284 )
274285}
275286
276- private predicate arrayStoreStepChi ( Node node1 , ArrayContent a , PostUpdateNode node2 ) {
287+ /**
288+ * A store step from a `StoreInstruction` to the `ChiInstruction` generated from assigning
289+ * to a pointer or array indirection
290+ */
291+ private predicate arrayStoreStepChi ( Node node1 , ArrayContent a , PartialDefinitionNode node2 ) {
277292 a = TArrayContent ( ) and
278- exists ( ChiPartialOperand operand , ChiInstruction chi , StoreInstruction store |
293+ exists (
294+ ChiPartialOperand operand , ChiInstruction chi , StoreInstruction store , PartialDefinition pd
295+ |
296+ pd = node2 .getPartialDefinition ( ) and
279297 chi .getPartialOperand ( ) = operand and
280298 store = operand .getDef ( ) and
281299 node1 .asOperand ( ) = operand and
282300 // This `ChiInstruction` will always have a non-conflated result because both `ArrayStoreNode`
283301 // and `PointerStoreNode` require it in their characteristic predicates.
284- node2 .asInstruction ( ) = chi and
285- (
286- // `x[i] = taint()`
287- // This matches the characteristic predicate in `ArrayStoreNode`.
288- store .getDestinationAddress ( ) instanceof PointerAddInstruction
289- or
290- // `*p = taint()`
291- // This matches the characteristic predicate in `PointerStoreNode`.
292- store .getDestinationAddress ( ) .( CopyValueInstruction ) .getUnary ( ) instanceof LoadInstruction
293- )
302+ pd .getPreUpdateNode ( ) .asOperand ( ) = chi .getTotalOperand ( )
303+ |
304+ // `x[i] = taint()`
305+ // This matches the characteristic predicate in `ArrayStoreNode`.
306+ store .getDestinationAddress ( ) instanceof PointerAddInstruction
307+ or
308+ // `*p = taint()`
309+ // This matches the characteristic predicate in `PointerStoreNode`.
310+ store .getDestinationAddress ( ) .( CopyValueInstruction ) .getUnary ( ) instanceof LoadInstruction
294311 )
295312}
296313
@@ -300,82 +317,10 @@ private predicate arrayStoreStepChi(Node node1, ArrayContent a, PostUpdateNode n
300317 * value of `node1`.
301318 */
302319predicate storeStep ( Node node1 , Content f , PostUpdateNode node2 ) {
303- fieldStoreStepNoChi ( node1 , f , node2 ) or
304- fieldStoreStepChi ( node1 , f , node2 ) or
320+ instrToFieldNodeStoreStepNoChi ( node1 , f , node2 ) or
321+ instrToFieldNodeStoreStepChi ( node1 , f , node2 ) or
305322 arrayStoreStepChi ( node1 , f , node2 ) or
306- fieldStoreStepAfterArraySuppression ( node1 , f , node2 )
307- }
308-
309- // This predicate pushes the correct `FieldContent` onto the access path when the
310- // `suppressArrayRead` predicate has popped off an `ArrayContent`.
311- private predicate fieldStoreStepAfterArraySuppression (
312- Node node1 , FieldContent f , PostUpdateNode node2
313- ) {
314- exists ( WriteSideEffectInstruction write , ChiInstruction chi , Class c |
315- not chi .isResultConflated ( ) and
316- node1 .asInstruction ( ) = chi and
317- node2 .asInstruction ( ) = chi and
318- chi .getPartial ( ) = write and
319- getWrittenField ( write , f .getAField ( ) , c ) and
320- f .hasOffset ( c , _, _)
321- )
322- }
323-
324- bindingset [ result , i]
325- private int unbindInt ( int i ) { i <= result and i >= result }
326-
327- pragma [ noinline]
328- private predicate getLoadedField ( LoadInstruction load , Field f , Class c ) {
329- exists ( FieldAddressInstruction fa |
330- fa = load .getSourceAddress ( ) and
331- f = fa .getField ( ) and
332- c = f .getDeclaringType ( )
333- )
334- }
335-
336- /**
337- * Holds if data can flow from `node1` to `node2` via a read of `f`.
338- * Thus, `node1` references an object with a field `f` whose value ends up in
339- * `node2`.
340- */
341- private predicate fieldReadStep ( Node node1 , FieldContent f , Node node2 ) {
342- exists ( LoadOperand operand |
343- node2 .asOperand ( ) = operand and
344- node1 .asInstruction ( ) = operand .getAnyDef ( ) and
345- exists ( Class c |
346- c = operand .getAnyDef ( ) .getResultType ( ) and
347- exists ( int startBit , int endBit |
348- operand .getUsedInterval ( unbindInt ( startBit ) , unbindInt ( endBit ) ) and
349- f .hasOffset ( c , startBit , endBit )
350- )
351- or
352- getLoadedField ( operand .getUse ( ) , f .getAField ( ) , c ) and
353- f .hasOffset ( c , _, _)
354- )
355- )
356- }
357-
358- /**
359- * When a store step happens in a function that looks like an array write such as:
360- * ```cpp
361- * void f(int* pa) {
362- * pa = source();
363- * }
364- * ```
365- * it can be a write to an array, but it can also happen that `f` is called as `f(&a.x)`. If that is
366- * the case, the `ArrayContent` that was written by the call to `f` should be popped off the access
367- * path, and a `FieldContent` containing `x` should be pushed instead.
368- * So this case pops `ArrayContent` off the access path, and the `fieldStoreStepAfterArraySuppression`
369- * predicate in `storeStep` ensures that we push the right `FieldContent` onto the access path.
370- */
371- predicate suppressArrayRead ( Node node1 , ArrayContent a , Node node2 ) {
372- a = TArrayContent ( ) and
373- exists ( WriteSideEffectInstruction write , ChiInstruction chi |
374- node1 .asInstruction ( ) = write and
375- node2 .asInstruction ( ) = chi and
376- chi .getPartial ( ) = write and
377- getWrittenField ( write , _, _)
378- )
323+ callableWithoutDefinitionStoreStep ( node1 , f , node2 )
379324}
380325
381326private class ArrayToPointerConvertInstruction extends ConvertInstruction {
0 commit comments