@@ -192,6 +192,37 @@ private class UnsignedMulExpr extends MulExpr {
192192 }
193193}
194194
195+ /**
196+ * Gets the value of the `EOF` macro.
197+ *
198+ * This is typically `"-1"`, but this is not guaranteed to be the case on all
199+ * systems.
200+ */
201+ private int getEofValue ( ) {
202+ exists ( MacroInvocation mi |
203+ mi .getMacroName ( ) = "EOF" and
204+ result = unique( | | mi .getExpr ( ) .getValue ( ) .toInt ( ) )
205+ )
206+ }
207+
208+ /** Get standard `getc` function or related variants. */
209+ private class Getc extends Function {
210+ Getc ( ) { this .hasGlobalOrStdOrBslName ( [ "fgetc" , "getc" ] ) }
211+ }
212+
213+ /** A call to `getc` */
214+ private class CallToGetc extends FunctionCall {
215+ CallToGetc ( ) { this .getTarget ( ) instanceof Getc }
216+ }
217+
218+ /**
219+ * A call to `getc` that we can analyze because we know
220+ * the value of the `EOF` macro.
221+ */
222+ private class AnalyzableCallToGetc extends CallToGetc {
223+ AnalyzableCallToGetc ( ) { exists ( getEofValue ( ) ) }
224+ }
225+
195226/**
196227 * Holds if `expr` is effectively a multiplication of `operand` with the
197228 * positive constant `positive`.
@@ -287,6 +318,8 @@ private predicate analyzableExpr(Expr e) {
287318 or
288319 e instanceof RemExpr
289320 or
321+ e instanceof AnalyzableCallToGetc
322+ or
290323 // A conversion is analyzable, provided that its child has an arithmetic
291324 // type. (Sometimes the child is a reference type, and so does not get
292325 // any bounds.) Rather than checking whether the type of the child is
@@ -861,6 +894,14 @@ private float getLowerBoundsImpl(Expr expr) {
861894 )
862895 )
863896 or
897+ exists ( AnalyzableCallToGetc getc |
898+ expr = getc and
899+ // from https://en.cppreference.com/w/c/io/fgetc:
900+ // On success, returns the obtained character as an unsigned char
901+ // converted to an int. On failure, returns EOF.
902+ result = min ( [ typeLowerBound ( any ( UnsignedCharType pct ) ) , getEofValue ( ) ] )
903+ )
904+ or
864905 // If the conversion is to an arithmetic type then we just return the
865906 // lower bound of the child. We do not need to handle truncation and
866907 // overflow here, because that is done in `getTruncatedLowerBounds`.
@@ -1055,6 +1096,14 @@ private float getUpperBoundsImpl(Expr expr) {
10551096 )
10561097 )
10571098 or
1099+ exists ( AnalyzableCallToGetc getc |
1100+ expr = getc and
1101+ // from https://en.cppreference.com/w/c/io/fgetc:
1102+ // On success, returns the obtained character as an unsigned char
1103+ // converted to an int. On failure, returns EOF.
1104+ result = max ( [ typeUpperBound ( any ( UnsignedCharType pct ) ) , getEofValue ( ) ] )
1105+ )
1106+ or
10581107 // If the conversion is to an arithmetic type then we just return the
10591108 // upper bound of the child. We do not need to handle truncation and
10601109 // overflow here, because that is done in `getTruncatedUpperBounds`.
0 commit comments