Skip to content

Commit f7392d6

Browse files
committed
C++: Range analysis of 'getc'.
1 parent 6ca978e commit f7392d6

File tree

1 file changed

+49
-0
lines changed

1 file changed

+49
-0
lines changed

cpp/ql/lib/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)