Skip to content

Commit 63afe1d

Browse files
authored
Merge pull request #4276 from geoffw0/stringstream3
C++: More stringstream models.
2 parents 86404af + c17ae3a commit 63afe1d

File tree

7 files changed

+294
-31
lines changed

7 files changed

+294
-31
lines changed

change-notes/1.26/analysis-cpp.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ The following changes in version 1.26 affect C/C++ analysis in all applications.
2323
* The QL class `Block`, denoting the `{ ... }` statement, is renamed to `BlockStmt`.
2424
* The models library now models many taint flows through `std::array`, `std::vector`, `std::deque`, `std::list` and `std::forward_list`.
2525
* The models library now models many more taint flows through `std::string`.
26-
* The models library now models some taint flows through `std::ostream`.
26+
* The models library now models many taint flows through `std::istream` and `std::ostream`.
2727
* The models library now models some taint flows through `std::shared_ptr`, `std::unique_ptr`, `std::make_shared` and `std::make_unique`.
2828
* The `SimpleRangeAnalysis` library now supports multiplications of the form
2929
`e1 * e2` and `x *= e2` when `e1` and `e2` are unsigned or constant.

cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll

Lines changed: 151 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -256,10 +256,13 @@ class StdStringSubstr extends TaintFunction {
256256
}
257257

258258
/**
259-
* The standard function `std::string.swap`.
259+
* The standard functions `std::string.swap` and `std::stringstream::swap`.
260260
*/
261261
class StdStringSwap extends TaintFunction {
262-
StdStringSwap() { this.hasQualifiedName("std", "basic_string", "swap") }
262+
StdStringSwap() {
263+
this.hasQualifiedName("std", "basic_string", "swap") or
264+
this.hasQualifiedName("std", "basic_stringstream", "swap")
265+
}
263266

264267
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
265268
// str1.swap(str2)
@@ -288,6 +291,151 @@ class StdStringAt extends TaintFunction {
288291
}
289292
}
290293

294+
/**
295+
* The `std::basic_istream` template class.
296+
*/
297+
class StdBasicIStream extends TemplateClass {
298+
StdBasicIStream() { this.hasQualifiedName("std", "basic_istream") }
299+
}
300+
301+
/**
302+
* The `std::istream` function `operator>>` (defined as a member function).
303+
*/
304+
class StdIStreamIn extends DataFlowFunction, TaintFunction {
305+
StdIStreamIn() { this.hasQualifiedName("std", "basic_istream", "operator>>") }
306+
307+
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
308+
// returns reference to `*this`
309+
input.isQualifierAddress() and
310+
output.isReturnValue()
311+
}
312+
313+
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
314+
// flow from qualifier to first parameter
315+
input.isQualifierObject() and
316+
output.isParameterDeref(0)
317+
or
318+
// reverse flow from returned reference to the qualifier
319+
input.isReturnValueDeref() and
320+
output.isQualifierObject()
321+
}
322+
}
323+
324+
/**
325+
* The `std::istream` function `operator>>` (defined as a non-member function).
326+
*/
327+
class StdIStreamInNonMember extends DataFlowFunction, TaintFunction {
328+
StdIStreamInNonMember() {
329+
this.hasQualifiedName("std", "operator>>") and
330+
this.getUnspecifiedType().(ReferenceType).getBaseType() =
331+
any(StdBasicIStream s).getAnInstantiation()
332+
}
333+
334+
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
335+
// flow from first parameter to return value
336+
input.isParameter(0) and
337+
output.isReturnValue()
338+
}
339+
340+
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
341+
// flow from first parameter to second parameter
342+
input.isParameterDeref(0) and
343+
output.isParameterDeref(1)
344+
or
345+
// reverse flow from returned reference to the first parameter
346+
input.isReturnValueDeref() and
347+
output.isParameterDeref(0)
348+
}
349+
}
350+
351+
/**
352+
* The `std::istream` functions `get` (without parameters) and `peek`.
353+
*/
354+
class StdIStreamGet extends TaintFunction {
355+
StdIStreamGet() {
356+
this.hasQualifiedName("std", "basic_istream", ["get", "peek"]) and
357+
this.getNumberOfParameters() = 0
358+
}
359+
360+
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
361+
// flow from qualifier to return value
362+
input.isQualifierObject() and
363+
output.isReturnValue()
364+
}
365+
}
366+
367+
/**
368+
* The `std::istream` functions `get` (with parameters) and `read`.
369+
*/
370+
class StdIStreamRead extends DataFlowFunction, TaintFunction {
371+
StdIStreamRead() {
372+
this.hasQualifiedName("std", "basic_istream", ["get", "read"]) and
373+
this.getNumberOfParameters() > 0
374+
}
375+
376+
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
377+
// returns reference to `*this`
378+
input.isQualifierAddress() and
379+
output.isReturnValue()
380+
}
381+
382+
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
383+
// flow from qualifier to first parameter
384+
input.isQualifierObject() and
385+
output.isParameterDeref(0)
386+
or
387+
// reverse flow from returned reference to the qualifier
388+
input.isReturnValueDeref() and
389+
output.isQualifierObject()
390+
}
391+
}
392+
393+
/**
394+
* The `std::istream` function `readsome`.
395+
*/
396+
class StdIStreamReadSome extends TaintFunction {
397+
StdIStreamReadSome() { this.hasQualifiedName("std", "basic_istream", "readsome") }
398+
399+
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
400+
// flow from qualifier to first parameter
401+
input.isQualifierObject() and
402+
output.isParameterDeref(0)
403+
}
404+
}
405+
406+
/**
407+
* The `std::istream` function `putback`.
408+
*/
409+
class StdIStreamPutBack extends DataFlowFunction, TaintFunction {
410+
StdIStreamPutBack() { this.hasQualifiedName("std", "basic_istream", "putback") }
411+
412+
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
413+
// returns reference to `*this`
414+
input.isQualifierAddress() and
415+
output.isReturnValue()
416+
}
417+
418+
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
419+
// flow from first parameter (value or pointer) to qualifier
420+
input.isParameter(0) and
421+
output.isQualifierObject()
422+
or
423+
input.isParameterDeref(0) and
424+
output.isQualifierObject()
425+
or
426+
// flow from first parameter (value or pointer) to return value
427+
input.isParameter(0) and
428+
output.isReturnValueDeref()
429+
or
430+
input.isParameterDeref(0) and
431+
output.isReturnValueDeref()
432+
or
433+
// reverse flow from returned reference to the qualifier
434+
input.isReturnValueDeref() and
435+
output.isQualifierObject()
436+
}
437+
}
438+
291439
/**
292440
* The `std::basic_ostream` template class.
293441
*/
@@ -303,7 +451,7 @@ class StdOStreamOut extends DataFlowFunction, TaintFunction {
303451
StdOStreamOut() { this.hasQualifiedName("std", "basic_ostream", ["operator<<", "put", "write"]) }
304452

305453
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
306-
// flow from qualifier to return value
454+
// returns reference to `*this`
307455
input.isQualifierAddress() and
308456
output.isReturnValue()
309457
}

0 commit comments

Comments
 (0)