Szelethus added a comment.

In D75045#1891064 <https://reviews.llvm.org/D75045#1891064>, @balazske wrote:

> In D75045#1891056 <https://reviews.llvm.org/D75045#1891056>, @NoQ wrote:
>
> > In D75045#1891055 <https://reviews.llvm.org/D75045#1891055>, @NoQ wrote:
> >
> > > How many such platforms can you name?
> >
> >
> > I mean, does Clang even support such targets?
>
>
> The problem can occur with the "wide" variants of the getc functions when 
> `wchar_t` is same width as `wint_t`, this can be more often (but I am not 
> sure). Even then the character set should contain a character similar to 
> `WEOF`, that is not true for UTF-16 and 32. So there may be low probability 
> for the problem to occur. Is this reason to not have this check at all?


If we can detect that the code is non-portable, it doesn't really matter in my 
opinion if we don't support the target on which the problem would occur. Also, 
I can't come up with a specific platform that would have an issue like this 
(maybe in a dishwasher? (: ), but CERT is known to create rules based on real 
vulnerabilities. A quick glance lead me to this page, though these 
vulnerabilities may not be directly related to this rule:

https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-ISO/IECTS17961-2013

In D75045#1891032 <https://reviews.llvm.org/D75045#1891032>, @balazske wrote:

> An improvement can be made if the check runs only when size of `char` and 
> `int` are equal.


Since the rule specifically states that the problem here is portability 
related, I think we shouldn't do that.

> The code can be improved somewhat but there are now too many special cases 
> and there is already a default eval function. Probably it is better to have 
> every "check" function take and return `ExplodedNode` instead of state.

This really ties into my main concern, that this **isn't** a stream management 
function specific problem, but rather an unchecked stream problem **after** we 
know that it returns `EOF`. I think we should first emit warnings on operations 
on `EOF`-returning streams, and implement this rule after that. WDYT?



================
Comment at: clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp:255-261
+  if (EOFv == 0) {
+    if (const llvm::Optional<int> OptInt =
+            tryExpandAsInteger("EOF", C.getPreprocessor()))
+      EOFv = *OptInt;
+    else
+      EOFv = -1;
+  }
----------------
balazske wrote:
> Szelethus wrote:
> > I'm 99% sure that the `Preprocessor` is retrievable in the checker registry 
> > function (`register*Checker`), and this code should be moved there, and 
> > `EOFv ` be made non-mutable. 
> I am not sure if this would be good. The `Preprocessor` is not available 
> easily and the "register" function is probably there to register a checker 
> and do nothing else. Probably the source code is not even known when it is 
> called. And how to pass the EOF value to the created checker in the register 
> function (if not a static variable is used)?
`CheckerManager::registerChecker` in fact returns the non-const checker object. 
The registry function is responsible for the registration //and// 
initialization of the checker object.

Though you have a point in the sense that this isn't terribly well defined (I 
should really finish D58065...).

I had a look, and my usual motto of //"Any manager can be retrieved in clang at 
arbitrary locations if you try hard enough"// seems to have been wrong. I don't 
see how I could get my hands on a `Preprocessor` in the checker registry 
function. So, feel free to disregard this comment.


================
Comment at: clang/test/Analysis/stream.c:188
+    C = fgetc(fp);
+    fread(0, 0, 0, fp); // expected-warning {{Should call}}
+    fread(0, 0, 0, fp);
----------------
balazske wrote:
> Szelethus wrote:
> > Are we sure that this is the error message we want to emit here? Sure, not 
> > checking whether the stream is in an error state is a recipe for disaster, 
> > but this seems to clash with
> > > Should call 'feof' and 'ferror' after failed character read.
> > as error here is not even checking the return value. Shouldn't we say
> > > Should check the return value of `fgetc` before ...
> > instead?
> No, it is not enough to check the return value of `fgetc`, exactly this is 
> the reason for the checker. "Should call 'feof' and 'ferror' after failed 
> character read." is more exact: The read was suspected to fail because EOF 
> was returned but should call feof (...) to verify it. A better message can be:
> 
> If 'fgetc' returns EOF call 'feof' and 'ferror' to check for error.
The compliant solution in the rule description has the following example:

```lang=c++

#include <stdio.h>
 
void func(void) {
  int c;
 
  do {
    c = getchar();
  } while (c != EOF);
  if (feof(stdin)) {
    /* Handle end of file */
  } else if (ferror(stdin)) {
    /* Handle file error */
  } else {
    /* Received a character that resembles EOF; handle error */
  }
}
```
because if the character resembles `EOF` that is an error too, and also

> Calling both functions on each iteration of a loop adds significant overhead, 
> so a good strategy is to temporarily trust EOF and WEOF within the loop but 
> verify them with feof() and ferror() following the loop.

Which makes me thing that the error here is not checking against `EOF`, first 
and foremost.

The warning message

>If 'fgetc' returns EOF call 'feof' and 'ferror' to check for error.

sounds great, I would just prefer to see it //after// we **know** that the 
stream returned `EOF`.


================
Comment at: clang/test/Analysis/stream.c:246-247
+    if (C == EOF) {
+      feof(fp);
+      ferror(fp);
+    }
----------------
balazske wrote:
> Szelethus wrote:
> > I bet this isn't how we envision how these function to be used. Maybe 
> > `ReturnValueChecker` could be deployed here? In any case, that would be a 
> > topic of a different revision.
> If `fgetc` returns non-EOF we can be sure that there is no error, so no need 
> to call `ferror` and `feof`. If it returns EOF we must "double-check" that it 
> was a real error or an EOF-looking character that was read.
Yea, but shouldn't we check the return values of `ferror` and `feof`? Otherwise 
whats the point?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75045/new/

https://reviews.llvm.org/D75045



_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to