Skip to content

[analyzer] False Positives due to conflicting assumptions in callee and caller about returned value's field #153782

@marco-antognini-sonarsource

Description

#115917 introduced a regression with the following code:

typedef struct { int error; } Status;
Status getError();
int global;

Status get(int **outptr) {
  Status e = getError();
  if (e.error != 0) return e; // field error is assumed to be non 0
  *outptr = &global; // therefore this is not executed
  return e;
}

int func() {
  int *ptr = 0;
  if (get(&ptr).error == 0) // field error is assumed to be 0
    return *ptr; // therefore this is a null deref
  return 0;
}

https://godbolt.org/z/seaaeMrTd

Another example with another Checker:

typedef struct {
  int v;
} STATUS;

STATUS STATUS_OK = {0};

void use(const char* x);

STATUS get_two(const char** ret);

static STATUS get_one(const char** ret) {
  STATUS status;
  const char* s;

  status = get_two(&s);
  if (status.v != 0) {
    return status;
  }

  *ret = s;

  return STATUS_OK;
}

int main() {
  STATUS status;
  const char* s;

  status = get_one(&s);
  if (status.v == 0) {
    use(s);  // FP
  }
}

https://godbolt.org/z/8x5Ghh95b

FYI The godbolt links show the difference between trunk and v19. I've done the bisection locally down to 4610e5c.

This issue impact many projects that have struct to represent error codes. I've often seen them wrapped with macros, such as in the Samba project. https://github.com/samba-team/samba/blob/7b5cc7d37f11347a606a4a9fe7f44ae43193318d/libcli/util/werror.h#L66

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions