diff --git a/go/ql/lib/semmle/go/controlflow/ControlFlowGraph.qll b/go/ql/lib/semmle/go/controlflow/ControlFlowGraph.qll index 9cf9633daa2..df9a025915e 100644 --- a/go/ql/lib/semmle/go/controlflow/ControlFlowGraph.qll +++ b/go/ql/lib/semmle/go/controlflow/ControlFlowGraph.qll @@ -188,9 +188,7 @@ module ControlFlow { * initialized. */ predicate writesElement(DataFlow::Node base, DataFlow::Node index, DataFlow::Node rhs) { - exists(DataFlow::Node b | - this.writesElementInsn(b.asInstruction(), index.asInstruction(), rhs.asInstruction()) - | + exists(DataFlow::Node b | this.writesElementPreUpdate(b, index, rhs) | this.isInitialization() and base = b or not this.isInitialization() and @@ -198,6 +196,21 @@ module ControlFlow { ) } + /** + * Holds if this node sets the value of element `index` on `base` (or its implicit dereference) + * to `rhs`. + * + * For example, for the assignment `xs[i] = v`, `base` is the post-update node of the data-flow + * node corresponding to `xs` or (if `xs` is a pointer) the implicit dereference `*xs`, `index` + * is the data-flow node corresponding to `i`, and `rhs` is the data-flow node corresponding to + * `base`. If this `WriteNode` corresponds to the initialization of an array/slice/map then + * there is no need for a post-update node and `base` is the array/slice/map literal being + * initialized. + */ + predicate writesElementPreUpdate(DataFlow::Node base, DataFlow::Node index, DataFlow::Node rhs) { + this.writesElementInsn(base.asInstruction(), index.asInstruction(), rhs.asInstruction()) + } + private predicate writesElementInsn( IR::Instruction base, IR::Instruction index, IR::Instruction rhs ) { diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/NetHttp.qll b/go/ql/lib/semmle/go/frameworks/stdlib/NetHttp.qll index 0ba122006e6..88c9605502f 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/NetHttp.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/NetHttp.qll @@ -52,13 +52,7 @@ module NetHttp { MapWrite() { this.getType().hasQualifiedName("net/http", "Header") and - exists(Write write, DataFlow::Node base | - write.writesElement(base, index, rhs) and - // The following line works because `Http::HeaderWrite::Range` extends - // `DataFlow::ExprNode`, which is incompatible with - // `DataFlow::PostUpdateNode`. - this = [base, base.(DataFlow::PostUpdateNode).getPreUpdateNode()] - ) + any(Write write).writesElementPreUpdate(this, index, rhs) } override DataFlow::Node getName() { result = index }