diff --git a/cpp/ql/lib/change-notes/2026-09-14-bdlcc-models.md b/cpp/ql/lib/change-notes/2026-09-14-bdlcc-models.md new file mode 100644 index 000000000000..2994cfd242e0 --- /dev/null +++ b/cpp/ql/lib/change-notes/2026-09-14-bdlcc-models.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Added data-flow models for single-element operations on BDE `bdlcc::Deque` and `bdlcc::BoundedQueue`. diff --git a/cpp/ql/lib/ext/bdlcc.model.yml b/cpp/ql/lib/ext/bdlcc.model.yml new file mode 100644 index 000000000000..f081c1276876 --- /dev/null +++ b/cpp/ql/lib/ext/bdlcc.model.yml @@ -0,0 +1,31 @@ +# BDE single-element concurrent queue operations (C++11 reference overloads). +# https://github.com/bloomberg/bde/tree/ec310b87e008199ecbdbc00a0b0264a53d806a0a/groups/bdl/bdlcc +extensions: + - addsTo: + pack: codeql/cpp-all + extensible: summaryModel + data: + - ["BloombergLP::bdlcc", "Deque", False, "pushBack", "(const T &)", "", "Argument[*@0]", "Argument[-1].Element[@]", "value", "manual"] + - ["BloombergLP::bdlcc", "Deque", False, "pushBack", "(T &&)", "", "Argument[*@0]", "Argument[-1].Element[@]", "value", "manual"] + - ["BloombergLP::bdlcc", "Deque", False, "pushFront", "(const T &)", "", "Argument[*@0]", "Argument[-1].Element[@]", "value", "manual"] + - ["BloombergLP::bdlcc", "Deque", False, "pushFront", "(T &&)", "", "Argument[*@0]", "Argument[-1].Element[@]", "value", "manual"] + - ["BloombergLP::bdlcc", "Deque", False, "forcePushBack", "(const T &)", "", "Argument[*@0]", "Argument[-1].Element[@]", "value", "manual"] + - ["BloombergLP::bdlcc", "Deque", False, "forcePushBack", "(T &&)", "", "Argument[*@0]", "Argument[-1].Element[@]", "value", "manual"] + - ["BloombergLP::bdlcc", "Deque", False, "forcePushFront", "(const T &)", "", "Argument[*@0]", "Argument[-1].Element[@]", "value", "manual"] + - ["BloombergLP::bdlcc", "Deque", False, "forcePushFront", "(T &&)", "", "Argument[*@0]", "Argument[-1].Element[@]", "value", "manual"] + - ["BloombergLP::bdlcc", "Deque", False, "tryPushBack", "(const T &)", "", "Argument[*@0]", "Argument[-1].Element[@]", "value", "manual"] + - ["BloombergLP::bdlcc", "Deque", False, "tryPushBack", "(T &&)", "", "Argument[*@0]", "Argument[-1].Element[@]", "value", "manual"] + - ["BloombergLP::bdlcc", "Deque", False, "popBack", "(T *)", "", "Argument[-1].Element[@]", "Argument[*@0]", "value", "manual"] + - ["BloombergLP::bdlcc", "Deque", False, "popFront", "(T *)", "", "Argument[-1].Element[@]", "Argument[*@0]", "value", "manual"] + - ["BloombergLP::bdlcc", "Deque", False, "tryPopBack", "(T *)", "", "Argument[-1].Element[@]", "Argument[*@0]", "value", "manual"] + - ["BloombergLP::bdlcc", "Deque", False, "tryPopFront", "(T *)", "", "Argument[-1].Element[@]", "Argument[*@0]", "value", "manual"] + - ["BloombergLP::bdlcc", "BoundedQueue", False, "pushBack", "(const T &)", "", "Argument[*@0]", "Argument[-1].Element[@]", "value", "manual"] + - ["BloombergLP::bdlcc", "BoundedQueue", False, "pushBack", "(T &&)", "", "Argument[*@0]", "Argument[-1].Element[@]", "value", "manual"] + - ["BloombergLP::bdlcc", "BoundedQueue", False, "tryPushBack", "(const T &)", "", "Argument[*@0]", "Argument[-1].Element[@]", "value", "manual"] + - ["BloombergLP::bdlcc", "BoundedQueue", False, "tryPushBack", "(T &&)", "", "Argument[*@0]", "Argument[-1].Element[@]", "value", "manual"] + - ["BloombergLP::bdlcc", "BoundedQueue", False, "popFront", "(T *)", "", "Argument[-1].Element[@]", "Argument[*@0]", "value", "manual"] + - ["BloombergLP::bdlcc", "BoundedQueue", False, "tryPopFront", "(T *)", "", "Argument[-1].Element[@]", "Argument[*@0]", "value", "manual"] + - ["BloombergLP::bdlcc", "Deque", False, "popBack", "", "", "Argument[-1].Element[]", "ReturnValue", "value", "manual"] + - ["BloombergLP::bdlcc", "Deque", False, "popFront", "", "", "Argument[-1].Element[]", "ReturnValue", "value", "manual"] + - ["BloombergLP::bdlcc", "Deque", False, "popBack", "", "", "Argument[-1].Element[*@]", "ReturnValue[*@]", "value", "manual"] + - ["BloombergLP::bdlcc", "Deque", False, "popFront", "", "", "Argument[-1].Element[*@]", "ReturnValue[*@]", "value", "manual"] diff --git a/cpp/ql/test/library-tests/dataflow/bdlcc/flow.expected b/cpp/ql/test/library-tests/dataflow/bdlcc/flow.expected new file mode 100644 index 000000000000..8b137891791f --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/bdlcc/flow.expected @@ -0,0 +1 @@ + diff --git a/cpp/ql/test/library-tests/dataflow/bdlcc/flow.ql b/cpp/ql/test/library-tests/dataflow/bdlcc/flow.ql new file mode 100644 index 000000000000..6bdf085e721b --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/bdlcc/flow.ql @@ -0,0 +1,19 @@ +import cpp +import utils.test.dataflow.FlowTestCommon +import semmle.code.cpp.ir.dataflow.TaintTracking + +module Config implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node node) { + node.asExpr().(FunctionCall).getTarget().hasName("source") + } + + predicate isSink(DataFlow::Node node) { + exists(FunctionCall call | + call.getTarget().hasName("sink") and node.asExpr() = call.getArgument(0) + ) + } +} + +module Flow = TaintTracking::Global; + +import MakeTest> diff --git a/cpp/ql/test/library-tests/dataflow/bdlcc/queues.h b/cpp/ql/test/library-tests/dataflow/bdlcc/queues.h new file mode 100644 index 000000000000..ccf22fe89b1b --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/bdlcc/queues.h @@ -0,0 +1,34 @@ +// Public single-element overloads from bloomberg/bde groups/bdl/bdlcc. +namespace BloombergLP { namespace bslma { class Allocator; } namespace bdlcc { +template class Deque { +public: + void pushBack(const TYPE& value); + void pushBack(TYPE&& value); + void pushFront(const TYPE& value); + void pushFront(TYPE&& value); + void forcePushBack(const TYPE& value); + void forcePushBack(TYPE&& value); + void forcePushFront(const TYPE& value); + void forcePushFront(TYPE&& value); + int tryPushBack(const TYPE& value); + int tryPushBack(TYPE&& value); + void popBack(TYPE *value); + void popFront(TYPE *value); + int tryPopBack(TYPE *value); + int tryPopFront(TYPE *value); + TYPE popBack(); + TYPE popFront(); + template void forcePushBack(ITER begin, ITER end); + void tryPopFront(unsigned long count); +}; +template class BoundedQueue { +public: + BoundedQueue(unsigned long capacity, bslma::Allocator *allocator = 0); + int pushBack(const TYPE& value); + int pushBack(TYPE&& value); + int tryPushBack(const TYPE& value); + int tryPushBack(TYPE&& value); + int popFront(TYPE *value); + int tryPopFront(TYPE *value); +}; +} } diff --git a/cpp/ql/test/library-tests/dataflow/bdlcc/ranges.cpp b/cpp/ql/test/library-tests/dataflow/bdlcc/ranges.cpp new file mode 100644 index 000000000000..f5b2cd1f2642 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/bdlcc/ranges.cpp @@ -0,0 +1,24 @@ +#include "queues.h" +int source(); +void sink(int); + +struct InputIterator { + int value; + const int &operator*() const { return value; } +}; + +// Reduced range overload body. The single-element models must not replace it. +namespace BloombergLP { namespace bdlcc { +template +template +void Deque::forcePushBack(ITER begin, ITER end) { + pushBack(*begin); +} +} } + +void rangeOverloadKeepsItsBody() { + BloombergLP::bdlcc::Deque q; + InputIterator begin = {source()}, end = {0}; + q.forcePushBack(begin, end); + sink(q.popFront()); // $ ir +} diff --git a/cpp/ql/test/library-tests/dataflow/bdlcc/test.cpp b/cpp/ql/test/library-tests/dataflow/bdlcc/test.cpp new file mode 100644 index 000000000000..52c75e502627 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/bdlcc/test.cpp @@ -0,0 +1,107 @@ +#include "queues.h" +int source(); +void sink(int); +using namespace BloombergLP::bdlcc; + +void DequepushBack() { + Deque q; + int input = source(), output = 0; + q.pushBack(input); + q.popBack(&output); + sink(output); // $ ir +} +void DequepushFront() { + Deque q; + int input = source(), output = 0; + q.pushFront(input); + q.popFront(&output); + sink(output); // $ ir +} +void DequeforcePushBack() { + Deque q; + int input = source(), output = 0; + q.forcePushBack(input); + q.tryPopBack(&output); + sink(output); // $ ir +} +void DequeforcePushFront() { + Deque q; + int input = source(), output = 0; + q.forcePushFront(input); + q.tryPopFront(&output); + sink(output); // $ ir +} +void DequetryPushBack() { + Deque q; + int input = source(), output = 0; + q.tryPushBack(input); + q.popBack(&output); + sink(output); // $ ir +} +void BoundedQueuepushBack() { + BoundedQueue q(8); + int input = source(), output = 0; + q.pushBack(input); + q.popFront(&output); + sink(output); // $ ir +} +void BoundedQueuetryPushBack() { + BoundedQueue q(8); + int input = source(), output = 0; + q.tryPushBack(input); + q.tryPopFront(&output); + sink(output); // $ ir +} + +void returnAndMove() { + Deque q; + int input = source(); + q.pushBack(static_cast(input)); + int output = 0; + q.popBack(&output); + sink(output); // $ ir + sink(q.popFront()); // $ ir + sink(q.popBack()); // $ ir +} +void returnAfterCopy() { + Deque q; + int input = source(); + q.pushBack(input); + sink(q.popFront()); // $ ir +} +void pointerPayload() { + int input = source(); + int *p = &input, *output = 0; + BoundedQueue q(8); + q.pushBack(p); + q.popFront(&output); + sink(*output); // $ ir +} +void pointerReturn() { + int input = source(); + int *p = &input; + Deque q; + q.pushBack(p); + sink(*q.popFront()); // $ ir +} +struct Payload { int value; }; +void objectPayload() { + Payload input = {source()}, output = {0}; + Deque q; + q.pushFront(input); + q.popBack(&output); + sink(output.value); // $ ir +} +void statusesAreNotPayload() { + BoundedQueue q(8); + int input = source(), output = 0; + sink(q.tryPushBack(input)); + sink(q.tryPopFront(&output)); + sink(output); // $ ir +} +void failureCanPreserveOutput() { + Deque q; + int output = source(); + if (q.tryPopFront(&output) != 0) + sink(output); // $ ir +} diff --git a/cpp/ql/test/library-tests/dataflow/external-models/validatemodels.expected b/cpp/ql/test/library-tests/dataflow/external-models/validatemodels.expected index d5b0b0cc0213..4ac97908c7ad 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/validatemodels.expected +++ b/cpp/ql/test/library-tests/dataflow/external-models/validatemodels.expected @@ -2437,6 +2437,7 @@ | Dubious signature "(Strent *)" in summary model. | | Dubious signature "(Strtab *,const char *,size_t)" in summary model. | | Dubious signature "(Strtab *,size_t *)" in summary model. | +| Dubious signature "(T &&)" in summary model. | | Dubious signature "(T *)" in summary model. | | Dubious signature "(T **)" in summary model. | | Dubious signature "(TLS_FEATURE *)" in summary model. | @@ -3691,6 +3692,7 @@ | Dubious signature "(const SSL_SESSION *,unsigned int *)" in summary model. | | Dubious signature "(const SXNET *,unsigned char **)" in summary model. | | Dubious signature "(const SXNETID *,unsigned char **)" in summary model. | +| Dubious signature "(const T &)" in summary model. | | Dubious signature "(const T &,BOOL)" in summary model. | | Dubious signature "(const TS_ACCURACY *)" in summary model. | | Dubious signature "(const TS_ACCURACY *,unsigned char **)" in summary model. |