@@ -418,6 +418,30 @@ class BaseCallVariable extends AbstractBaseSourceVariable, TBaseCallVariable {
418418}
419419
420420private module IsModifiableAtImpl {
421+ /**
422+ * Holds if the `indirectionIndex`'th dereference of a value of type
423+ * `cppType` is a type that can be modified (either by modifying the value
424+ * itself or one of its fields if it's a class type).
425+ *
426+ * For example, a value of type `const int* const` cannot be modified
427+ * at any indirection index (because it's a constant pointer to constant
428+ * data), and a value of type `int *const *` is modifiable at indirection index
429+ * 2 only.
430+ *
431+ * A value of type `const S2* s2` where `s2` is
432+ * ```cpp
433+ * struct S { int x; }
434+ * ```
435+ * can be modified at indirection index 1. This is to ensure that we generate
436+ * a `PostUpdateNode` for the argument corresponding to the `s2` parameter in
437+ * an example such as:
438+ * ```cpp
439+ * void set_field(const S2* s2)
440+ * {
441+ * s2->s->x = 42;
442+ * }
443+ * ```
444+ */
421445 bindingset [ cppType, indirectionIndex]
422446 pragma [ inline_late]
423447 private predicate impl ( CppType cppType , int indirectionIndex ) {
@@ -436,6 +460,18 @@ private module IsModifiableAtImpl {
436460 )
437461 }
438462
463+ /**
464+ * Holds if `cppType` is modifiable with an indirection index of at least 1.
465+ *
466+ * This predicate factored out into a seperate predicate for two reasons:
467+ * - This predicate needs to be recursive because, if a type is modifiable
468+ * at indirection `i`, then it's also modifiable at indirection index `i+1`
469+ * (because the pointer could be completely re-assigned at indirection `i`).
470+ * - We special-case indirection index `0` so that pointer arguments that can
471+ * be modified at some index always have a `PostUpdateNode` at indiretion
472+ * index 0 even though the 0'th indirection can never be modified by a
473+ * callee.
474+ */
439475 private predicate isModifiableAtImplAtLeast1 ( CppType cppType , int indirectionIndex ) {
440476 indirectionIndex = [ 1 .. countIndirectionsForCppType ( cppType ) ] and
441477 (
@@ -447,12 +483,21 @@ private module IsModifiableAtImpl {
447483 )
448484 }
449485
486+ /**
487+ * Holds if `cppType` is modifiable at indirection index 0.
488+ *
489+ * In reality, the 0'th indirection of a pointer (i.e., the pointer itself)
490+ * can never be modified by a callee, but it is sometimes useful to be able
491+ * to specify the value of the pointer, as its coming out of a function, as
492+ * a source of dataflow since the shared library's reverse-read mechanism
493+ * then ensures that field-flow is accounted for.
494+ */
450495 private predicate isModifiableAtImplAt0 ( CppType cppType ) { impl ( cppType , 0 ) }
451496
452497 /**
453- * Holds if `t` is a pointer or reference type that supports at least `indirectionIndex` number
454- * of indirections, and the `indirectionIndex` indirection cannot be modfiied by passing a
455- * value of `t` to a function.
498+ * Holds if `t` is a pointer or reference type that supports at least
499+ * `indirectionIndex` number of indirections, and the `indirectionIndex`
500+ * indirection cannot be modfiied by passing a value of `t` to a function.
456501 */
457502 private predicate isModifiableAtImpl ( CppType cppType , int indirectionIndex ) {
458503 isModifiableAtImplAtLeast1 ( cppType , indirectionIndex )
@@ -462,9 +507,9 @@ private module IsModifiableAtImpl {
462507 }
463508
464509 /**
465- * Holds if `t` is a type with at least `indirectionIndex` number of indirections,
466- * and the `indirectionIndex` indirection can be modified by passing a value of
467- * type `t` to a function function.
510+ * Holds if `t` is a type with at least `indirectionIndex` number of
511+ * indirections, and the `indirectionIndex` indirection can be modified by
512+ * passing a value of type `t` to a function function.
468513 */
469514 bindingset [ indirectionIndex]
470515 predicate isModifiableAt ( CppType cppType , int indirectionIndex ) {
0 commit comments