Skip to content

C/C++ data flow analysis doesn't produce paths #8498

@nrb547

Description

@nrb547

In the example below I am trying to analyze the data flow of the variable to_copy.
Consider this sample code:

int get_alert(char *buf, size_t buf_size)
{
  size_t to_copy;
  size_t copied;

  to_copy = buf_size;

  if (to_copy < 0) {
    printf("to_copy is corrupt\n");
    return -1;
  }

  if (to_copy > MAX_SIZE) {
    printf("to_copy is too big\n");
    return -1;
  }

  if (!check_buf(to_copy)) {
    printf("wrong copy size\n");
    return -1;
  }

  copied = copy_alert(buf, to_copy);

  buf[to_copy - 1] = '\0';

  return copied;
}

I would like to start at the assignment to_copy = buf_size; and receive
possible paths of where this variable is used.
For this reason, I wrote the following query:

/**
 * @kind path-problem
 */
import cpp
import semmle.code.cpp.dataflow.DataFlow
import DataFlow::PathGraph

class Config extends DataFlow::Configuration {
  Config() { this = "track to_copy" }

  /* source is VariableAccess of to_copy */
  override predicate isSource(DataFlow::Node source) {
    exists(AssignExpr ae, VariableAccess va |
      va = source.asExpr() and
      ae.getLValue() = va and
      va.getTarget().hasName("to_copy") and
      va.getEnclosingFunction().hasName("get_alert")
    )
  }
  
  /* no idea where it can end up */
  override predicate isSink(DataFlow::Node sink) {
    any()
  }
}

from Config cfg, DataFlow::PathNode source, DataFlow::PathNode sink
where
  cfg.hasFlowPath(source, sink)
select sink, source, sink, "possible path found"

Running a quick evaluation for isSource leads me to to_copy being assigned,
so this works.
But running the whole query only shows me an alert with the location of
the initial assignment:

image

I expected at least one path:
to_copy = buf_size; -> if (to_copy < 0) -> if (to_copy > MAX_SIZE)

Besides, I noticed that the data flow example in the documentation
uses FunctionCall as a source and the sink is an argument expression.

https://codeql.github.com/docs/codeql-language-guides/analyzing-data-flow-in-cpp/#id1

I thought source and sink would be required to be of the same type,
otherwise how can a source of FunctionCall become a sink of Argument?

Any help is appreciated.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions