This is an archive of the discontinued LLVM Phabricator instance.

[clang-tidy] Add fsetpos argument checker
Needs ReviewPublic

Authored by DerWaschbar on May 5 2020, 11:08 AM.

Details

Summary

According to https://wiki.sei.cmu.edu/confluence/x/x9UxBQ
bugprone-fsetpos-argument-check is created.
The check finds fsetpos() function calls where the argument
is not initialized with fgetpos()

Diff Detail

Event Timeline

DerWaschbar created this revision.May 5 2020, 11:08 AM

Please rebase from master. Current version is based on 9.0.

clang-tools-extra/clang-tidy/bugprone/FsetposArgumentCheck.cpp
13

Unnecessary empty line.

23

Unnecessary empty line.

clang-tools-extra/docs/ReleaseNotes.rst
200

Please use double back-ticks to highlight language constructs.

clang-tools-extra/docs/clang-tidy/checks/bugprone-fsetpos-argument-check.rst
7

Please use double back-ticks to highlight language constructs.

16

Please indent code.

38

Please add newline.

clang-tools-extra/docs/clang-tidy/checks/cert-fio44-c.rst
11

Please add newline.

Eugene.Zelenko edited reviewers, added: njames93; removed: jfb, Charusso.May 5 2020, 11:48 AM
Eugene.Zelenko added a subscriber: cfe-commits.
DerWaschbar marked 7 inline comments as done.
  • Removed unnecessary empty lines.
  • Added double back-ticks to highlight language constructs.
  • Indented code in documentation.
This comment was removed by DerWaschbar.

Thank you for working on this check, I think it's useful functionality. One concern I have, though, is that it's not flow-sensitive and should probably be implemented as a clang static analyzer check instead of a clang-tidy check. For instance, consider these three plausible issues:

// This only sets the offset on one code path.
void func(FILE *fp) {
  fpos_t offset;
  if (condition) {
    // ... code
    if (0 != fgetpos(fp, &offset))
      return;
    // ... code
  } else {
   // ... code
  }
  fsetpos(fp, &offset);
}

// This doesn't check the failure from getting the position and sets the position regardless.
void func(FILE *fp) {
  fpos_t offset;
  fgetpos(fp, &offset);
  // ... code
  fsetpos(fp, &offset);
}

// This function accepts the offset from the caller but the caller passes an invalid offset.
void func(FILE *fp, const fpos_t *offset) {
  fsetpos(fp, offset);
}
void caller(FILE *fp) {
  fpos_t offset;
  func(fp, &offset);
}

Have you considered writing a static analyzer check so you can do data and control flow analysis to catch issues like these?

clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
103

Can you reorder to below fio38-c?

clang-tools-extra/docs/clang-tidy/checks/bugprone-fsetpos-argument-check.rst
5

The underlines here don't look like they are correct.

36

the CERT C Coding Standard rule

DerWaschbar marked 3 inline comments as done.
mgehre removed a subscriber: mgehre.May 24 2020, 9:15 AM

Thank you for working on this check, I think it's useful functionality. One concern I have, though, is that it's not flow-sensitive and should probably be implemented as a clang static analyzer check instead of a clang-tidy check. For instance, consider these three plausible issues:

// This only sets the offset on one code path.
void func(FILE *fp) {
  fpos_t offset;
  if (condition) {
    // ... code
    if (0 != fgetpos(fp, &offset))
      return;
    // ... code
  } else {
   // ... code
  }
  fsetpos(fp, &offset);
}

// This doesn't check the failure from getting the position and sets the position regardless.
void func(FILE *fp) {
  fpos_t offset;
  fgetpos(fp, &offset);
  // ... code
  fsetpos(fp, &offset);
}

// This function accepts the offset from the caller but the caller passes an invalid offset.
void func(FILE *fp, const fpos_t *offset) {
  fsetpos(fp, offset);
}
void caller(FILE *fp) {
  fpos_t offset;
  func(fp, &offset);
}

Have you considered writing a static analyzer check so you can do data and control flow analysis to catch issues like these?

I have noticed those issues too, but most likely the getter/setter will be in the same function body and we could measure fast how common is that issue in the wild. Also, this was my first introductory project for Clang and with that, I can rewrite this as a Static Analyzer project or start working on another Clang-Tidy project.

Have you considered writing a static analyzer check so you can do data and control flow analysis to catch issues like these?

I have noticed those issues too, but most likely the getter/setter will be in the same function body and we could measure fast how common is that issue in the wild.

That doesn't match my intuition, but if you have data, that would be excellent for helping to make a decision.

Also, this was my first introductory project for Clang and with that, I can rewrite this as a Static Analyzer project or start working on another Clang-Tidy project.

Welcome! I think this functionality is likely useful in here as a clang-tidy check, but I'd be curious to see data on whether it finds true or false positives in the wild to help judge that. My gut instinct is that to do this properly, we'll want it in the static analyzer, but perhaps the tidy check is good enough. I'd be curious to know if others have different thoughts though (pinging @alexfh for visibility).

btw, if you're interested in exploring a static analyzer solution for this, here's a recent review of an analyzer feature that's in the same general problem space: https://reviews.llvm.org/D80018

dkrupp added a subscriber: dkrupp.Jul 3 2020, 5:13 AM
whisperity added inline comments.Jul 9 2020, 1:58 AM
clang-tools-extra/test/clang-tidy/checkers/bugprone-fsetpos-argument-check.cpp
1

This is a C, not a C++ file, the extension should show it. In addition, a similar test should be added that uses std::fgetpos() and std::fsetpos(), and shows the matching still works.

MTC added a subscriber: MTC.Aug 16 2021, 7:17 PM