Skip to content

Commit 3ee8ce8

Browse files
committed
C++: model BDE character views and substring utilities
1 parent b9cb90c commit 3ee8ce8

7 files changed

Lines changed: 158 additions & 0 deletions

File tree

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* Added models for BDE character-view construction and access, and `bdlb::StringRefUtil` trimming, substring, and search operations.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# BDE character views and substring utilities.
2+
extensions:
3+
- addsTo:
4+
pack: codeql/cpp-all
5+
extensible: summaryModel
6+
data:
7+
- ["BloombergLP::bslstl", "StringRefImp", False, "data", "", "", "Argument[-1].Element[]", "ReturnValue[*]", "value", "manual"]
8+
- ["BloombergLP::bslstl", "StringRefImp", False, "begin", "", "", "Argument[-1].Element[]", "ReturnValue[*]", "value", "manual"]
9+
- ["BloombergLP::bslstl", "StringRefImp", False, "operator[]", "", "", "Argument[-1].Element[]", "ReturnValue[*]", "value", "manual"]
10+
- ["BloombergLP::bdlb", "StringRefUtil", False, "trim", "", "", "Argument[*0].Element[]", "ReturnValue.Element[]", "value", "manual"]
11+
- ["BloombergLP::bdlb", "StringRefUtil", False, "ltrim", "", "", "Argument[*0].Element[]", "ReturnValue.Element[]", "value", "manual"]
12+
- ["BloombergLP::bdlb", "StringRefUtil", False, "rtrim", "", "", "Argument[*0].Element[]", "ReturnValue.Element[]", "value", "manual"]
13+
- ["BloombergLP::bdlb", "StringRefUtil", False, "substr", "", "", "Argument[*0].Element[]", "ReturnValue.Element[]", "value", "manual"]
14+
- ["BloombergLP::bdlb", "StringRefUtil", False, "strstr", "", "", "Argument[*0].Element[]", "ReturnValue.Element[]", "value", "manual"]
15+
- ["BloombergLP::bdlb", "StringRefUtil", False, "strrstr", "", "", "Argument[*0].Element[]", "ReturnValue.Element[]", "value", "manual"]
16+
- ["BloombergLP::bdlb", "StringRefUtil", False, "strstrCaseless", "", "", "Argument[*0].Element[]", "ReturnValue.Element[]", "value", "manual"]
17+
- ["BloombergLP::bdlb", "StringRefUtil", False, "strrstrCaseless", "", "", "Argument[*0].Element[]", "ReturnValue.Element[]", "value", "manual"]

cpp/ql/lib/semmle/code/cpp/models/Models.qll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,5 @@ private import implementations.CAtlTemporaryFile
5858
private import implementations.CRegKey
5959
private import implementations.WinHttp
6060
private import implementations.Http
61+
62+
private import implementations.BdlbStringRef
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/** Models construction of BDE character views. */
2+
3+
private import cpp
4+
private import semmle.code.cpp.dataflow.internal.FlowSummaryImpl::Public
5+
6+
/** Only pointer-based constructors read character data from their first argument. */
7+
private class CharacterViewConstructor extends SummarizedCallable {
8+
CharacterViewConstructor() {
9+
this instanceof Constructor and
10+
this.getDeclaringType().hasQualifiedName("BloombergLP::bslstl", "StringRefImp") and
11+
this.getParameter(0).getUnspecifiedType() instanceof PointerType
12+
}
13+
14+
override predicate propagatesFlow(
15+
string input, string output, boolean preservesValue, Provenance provenance, boolean isExact,
16+
string model
17+
) {
18+
input = "Argument[*0]" and
19+
output = "Argument[-1].Element[]" and
20+
preservesValue = true and
21+
provenance = "manual" and
22+
isExact = true and
23+
model = ""
24+
}
25+
}

cpp/ql/test/library-tests/dataflow/bdlb-stringref/flow.expected

Whitespace-only changes.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import cpp
2+
import utils.test.dataflow.FlowTestCommon
3+
import semmle.code.cpp.ir.dataflow.TaintTracking
4+
5+
module Config implements DataFlow::ConfigSig {
6+
predicate isSource(DataFlow::Node node) {
7+
node.asExpr().(FunctionCall).getTarget().hasName("source")
8+
}
9+
10+
predicate isSink(DataFlow::Node node) {
11+
exists(FunctionCall call |
12+
call.getTarget().hasName("sink") and node.asExpr() = call.getArgument(0)
13+
)
14+
}
15+
}
16+
17+
module Flow = TaintTracking::Global<Config>;
18+
19+
import MakeTest<IRFlowTest<Flow>>
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
// Reduced declarations from bslstl_stringref.h and bdlb_stringrefutil.h.
2+
namespace bsl {
3+
template<bool, class T> struct enable_if {};
4+
template<class T> struct enable_if<true, T> { typedef T type; };
5+
template<class T> struct is_integral { enum { value = false }; };
6+
template<> struct is_integral<int> { enum { value = true }; };
7+
}
8+
namespace BloombergLP {
9+
namespace bslmf { struct Nil {}; }
10+
namespace bslstl {
11+
template<class C> class StringRefImp {
12+
public:
13+
typedef unsigned long size_type;
14+
typedef const C *const_iterator;
15+
StringRefImp();
16+
StringRefImp(const C *);
17+
StringRefImp(const C *, size_type);
18+
// Integral overload: the upstream enable_if resolves to bslmf::Nil.
19+
template<class I> StringRefImp(const C *, I,
20+
typename bsl::enable_if<bsl::is_integral<I>::value, bslmf::Nil>::type = bslmf::Nil());
21+
StringRefImp(const_iterator, const_iterator);
22+
const C *data() const;
23+
const_iterator begin() const;
24+
const C& operator[](size_type) const;
25+
size_type length() const;
26+
};
27+
typedef StringRefImp<char> StringRef;
28+
}
29+
namespace bdlb {
30+
struct StringRefUtil {
31+
typedef unsigned long size_type;
32+
static bslstl::StringRef trim(const bslstl::StringRef&);
33+
static bslstl::StringRef ltrim(const bslstl::StringRef&);
34+
static bslstl::StringRef rtrim(const bslstl::StringRef&);
35+
static bslstl::StringRef substr(const bslstl::StringRef&, size_type = 0, size_type = -1);
36+
static bslstl::StringRef strstr(const bslstl::StringRef&, const bslstl::StringRef&);
37+
static bslstl::StringRef strrstr(const bslstl::StringRef&, const bslstl::StringRef&);
38+
static bslstl::StringRef strstrCaseless(const bslstl::StringRef&, const bslstl::StringRef&);
39+
static bslstl::StringRef strrstrCaseless(const bslstl::StringRef&, const bslstl::StringRef&);
40+
};
41+
}
42+
}
43+
using BloombergLP::bslstl::StringRef;
44+
using BloombergLP::bdlb::StringRefUtil;
45+
int source();
46+
void sink(int);
47+
48+
void views() {
49+
char buffer[] = {static_cast<char>(source()), 0};
50+
StringRef view(buffer);
51+
sink(view.data()[0]); // $ ir
52+
sink(view[0]); // $ ir
53+
sink(*view.begin()); // $ ir
54+
StringRef copy(view);
55+
sink(copy[0]); // $ ir
56+
StringRef sized(buffer, static_cast<unsigned long>(1));
57+
sink(sized[0]); // $ ir
58+
StringRef range(buffer, buffer + 1);
59+
sink(range[0]); // $ ir
60+
StringRef integral(buffer, 1);
61+
sink(integral[0]); // $ ir
62+
sink(view.length());
63+
sink(StringRefUtil::trim(view)[0]); // $ ir
64+
sink(StringRefUtil::ltrim(view)[0]); // $ ir
65+
sink(StringRefUtil::rtrim(view)[0]); // $ ir
66+
sink(StringRefUtil::substr(view)[0]); // $ ir
67+
sink(StringRefUtil::strstr(view, "x")[0]); // $ ir
68+
sink(StringRefUtil::strrstr(view, "x")[0]); // $ ir
69+
sink(StringRefUtil::strstrCaseless(view, "x")[0]); // $ ir
70+
sink(StringRefUtil::strrstrCaseless(view, "x")[0]); // $ ir
71+
}
72+
73+
void metadataAndPatterns() {
74+
unsigned long length = source();
75+
StringRef clean("clean", length);
76+
sink(clean[0]);
77+
sink(StringRefUtil::substr(clean, length, length)[0]);
78+
char buffer[] = {static_cast<char>(source()), 0};
79+
StringRef pattern(buffer);
80+
sink(StringRefUtil::strstr(clean, pattern)[0]);
81+
sink(StringRefUtil::strrstr(clean, pattern)[0]);
82+
sink(StringRefUtil::strstrCaseless(clean, pattern)[0]);
83+
sink(StringRefUtil::strrstrCaseless(clean, pattern)[0]);
84+
sink(StringRefUtil::strstr(clean, "missing").length());
85+
}
86+
87+
void wide() {
88+
wchar_t buffer[] = {static_cast<wchar_t>(source()), 0};
89+
BloombergLP::bslstl::StringRefImp<wchar_t> view(buffer);
90+
sink(view[0]); // $ ir
91+
}

0 commit comments

Comments
 (0)