Skip to content

Commit 25412da

Browse files
authored
Merge pull request #4253 from geoffw0/stringstream2
C++: Model more stringstream features
2 parents 1fbb0fb + 6b035df commit 25412da

File tree

6 files changed

+215
-51
lines changed

6 files changed

+215
-51
lines changed

cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -629,14 +629,25 @@ private predicate exprToExprStep_nocfg(Expr fromExpr, Expr toExpr) {
629629
// `ClassAggregateLiteral` (`{ capture1, ..., captureN }`).
630630
toExpr.(LambdaExpression).getInitializer() = fromExpr
631631
or
632+
// Data flow through a function model.
632633
toExpr =
633634
any(Call call |
634-
exists(DataFlowFunction f, FunctionInput inModel, FunctionOutput outModel, int iIn |
635-
call.getTarget() = f and
635+
exists(DataFlowFunction f, FunctionInput inModel, FunctionOutput outModel |
636636
f.hasDataFlow(inModel, outModel) and
637-
outModel.isReturnValue() and
638-
inModel.isParameter(iIn) and
639-
fromExpr = call.getArgument(iIn)
637+
(
638+
exists(int iIn |
639+
inModel.isParameter(iIn) and
640+
fromExpr = call.getArgument(iIn)
641+
)
642+
or
643+
inModel.isQualifierObject() and
644+
fromExpr = call.getQualifier()
645+
or
646+
inModel.isQualifierAddress() and
647+
fromExpr = call.getQualifier()
648+
) and
649+
call.getTarget() = f and
650+
outModel.isReturnValue()
640651
)
641652
)
642653
}

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

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -296,10 +296,11 @@ class StdBasicOStream extends TemplateClass {
296296
}
297297

298298
/**
299-
* The `std::ostream` function `operator<<` (defined as a member function).
299+
* The `std::ostream` functions `operator<<` (defined as a member function),
300+
* `put` and `write`.
300301
*/
301302
class StdOStreamOut extends DataFlowFunction, TaintFunction {
302-
StdOStreamOut() { this.hasQualifiedName("std", "basic_ostream", "operator<<") }
303+
StdOStreamOut() { this.hasQualifiedName("std", "basic_ostream", ["operator<<", "put", "write"]) }
303304

304305
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
305306
// flow from qualifier to return value
@@ -308,14 +309,20 @@ class StdOStreamOut extends DataFlowFunction, TaintFunction {
308309
}
309310

310311
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
311-
// flow from parameter to qualifier
312+
// flow from first parameter (value or pointer) to qualifier
312313
input.isParameter(0) and
313314
output.isQualifierObject()
314315
or
315-
// flow from parameter to return value
316+
input.isParameterDeref(0) and
317+
output.isQualifierObject()
318+
or
319+
// flow from first parameter (value or pointer) to return value
316320
input.isParameter(0) and
317321
output.isReturnValueDeref()
318322
or
323+
input.isParameterDeref(0) and
324+
output.isReturnValueDeref()
325+
or
319326
// reverse flow from returned reference to the qualifier
320327
input.isReturnValueDeref() and
321328
output.isQualifierObject()
@@ -352,3 +359,43 @@ class StdOStreamOutNonMember extends DataFlowFunction, TaintFunction {
352359
output.isParameterDeref(0)
353360
}
354361
}
362+
363+
/**
364+
* Additional model for `std::stringstream` constructors that take a string
365+
* input parameter.
366+
*/
367+
class StdStringStreamConstructor extends Constructor, TaintFunction {
368+
StdStringStreamConstructor() {
369+
this.getDeclaringType().hasQualifiedName("std", "basic_stringstream")
370+
}
371+
372+
/**
373+
* Gets the index of a parameter to this function that is a string.
374+
*/
375+
int getAStringParameterIndex() {
376+
getParameter(result).getType() instanceof ReferenceType // `const std::basic_string &`
377+
}
378+
379+
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
380+
// taint flow from any parameter of string type to the returned object
381+
input.isParameterDeref(getAStringParameterIndex()) and
382+
output.isReturnValue() // TODO: this should be `isQualifierObject` by our current definitions, but that flow is not yet supported.
383+
}
384+
}
385+
386+
/**
387+
* The `std::stringstream` function `str`.
388+
*/
389+
class StdStringStreamStr extends TaintFunction {
390+
StdStringStreamStr() { this.hasQualifiedName("std", "basic_stringstream", "str") }
391+
392+
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
393+
// flow from qualifier to return value (if any)
394+
input.isQualifierObject() and
395+
output.isReturnValue()
396+
or
397+
// flow from first parameter (if any) to qualifier
398+
input.isParameterDeref(0) and
399+
output.isQualifierObject()
400+
}
401+
}

0 commit comments

Comments
 (0)