From ed540dfcddc28de4cedd7725093dc0de74165e1d Mon Sep 17 00:00:00 2001 From: AkshayK Date: Thu, 27 Aug 2026 10:17:19 -0400 Subject: [PATCH 1/3] cpp: model Protocol Buffers parse/serialize taint flow Add flow summaries for the protobuf C++ API on google::protobuf::MessageLite (subtypes=true, so Message and all generated messages are covered): - ParseFrom*/MergeFrom* (string, array, Cord, istream, zero-copy and coded-stream forms) propagate taint from the encoded input to the message. - SerializeTo*/AppendTo* propagate taint from the message to the output buffer or stream; SerializeAs*/... to the return value. File-descriptor variants are omitted (the fd is an int, not a buffer). --- .../2026-08-27-protobuf-models.md | 4 + cpp/ql/lib/ext/Protobuf.model.yml | 58 +++++++++ .../dataflow/external-models/flow.expected | 47 +++++++ .../dataflow/external-models/protobuf.cpp | 122 ++++++++++++++++++ .../dataflow/external-models/steps.expected | 15 +++ 5 files changed, 246 insertions(+) create mode 100644 cpp/ql/lib/change-notes/2026-08-27-protobuf-models.md create mode 100644 cpp/ql/lib/ext/Protobuf.model.yml create mode 100644 cpp/ql/test/library-tests/dataflow/external-models/protobuf.cpp diff --git a/cpp/ql/lib/change-notes/2026-08-27-protobuf-models.md b/cpp/ql/lib/change-notes/2026-08-27-protobuf-models.md new file mode 100644 index 000000000000..a039b28de676 --- /dev/null +++ b/cpp/ql/lib/change-notes/2026-08-27-protobuf-models.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Added flow summaries for the Protocol Buffers C++ API (`google::protobuf::MessageLite`, covering `Message` and all generated messages). The `ParseFrom*`/`MergeFrom*` methods (string, array, Cord, istream, and zero-copy/coded-stream forms) propagate taint from the encoded input to the message, and the `SerializeTo*`/`SerializeAs*`/`AppendTo*` methods propagate taint from the message to the output buffer, stream, or return value. diff --git a/cpp/ql/lib/ext/Protobuf.model.yml b/cpp/ql/lib/ext/Protobuf.model.yml new file mode 100644 index 000000000000..b080855536a1 --- /dev/null +++ b/cpp/ql/lib/ext/Protobuf.model.yml @@ -0,0 +1,58 @@ +extensions: + - addsTo: + pack: codeql/cpp-all + extensible: summaryModel + data: # namespace, type, subtypes, name, signature, ext, input, output, kind, provenance + # Flow summaries for the Protocol Buffers C++ API. All of these methods are declared on + # `google::protobuf::MessageLite`; `subtypes` covers `Message` and every generated message. + # + # File-descriptor variants (`{Parse,Serialize}*FromFileDescriptor`) are intentionally omitted: + # the descriptor is an `int`, not a data buffer, so there is no buffer argument to model. + + # Deserialization: the encoded input (`Argument[*0]`) taints the message (`this`). + - ["google::protobuf", "MessageLite", True, "ParseFromString", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"] + - ["google::protobuf", "MessageLite", True, "ParsePartialFromString", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"] + - ["google::protobuf", "MessageLite", True, "MergeFromString", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"] + - ["google::protobuf", "MessageLite", True, "MergePartialFromString", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"] + - ["google::protobuf", "MessageLite", True, "ParseFromArray", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"] + - ["google::protobuf", "MessageLite", True, "ParsePartialFromArray", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"] + - ["google::protobuf", "MessageLite", True, "ParseFromCord", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"] + - ["google::protobuf", "MessageLite", True, "ParsePartialFromCord", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"] + - ["google::protobuf", "MessageLite", True, "MergeFromCord", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"] + - ["google::protobuf", "MessageLite", True, "MergePartialFromCord", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"] + - ["google::protobuf", "MessageLite", True, "ParseFromIstream", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"] + - ["google::protobuf", "MessageLite", True, "ParsePartialFromIstream", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"] + - ["google::protobuf", "MessageLite", True, "ParseFromZeroCopyStream", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"] + - ["google::protobuf", "MessageLite", True, "ParsePartialFromZeroCopyStream", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"] + - ["google::protobuf", "MessageLite", True, "ParseFromBoundedZeroCopyStream", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"] + - ["google::protobuf", "MessageLite", True, "ParsePartialFromBoundedZeroCopyStream", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"] + - ["google::protobuf", "MessageLite", True, "MergeFromBoundedZeroCopyStream", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"] + - ["google::protobuf", "MessageLite", True, "MergePartialFromBoundedZeroCopyStream", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"] + - ["google::protobuf", "MessageLite", True, "ParseFromCodedStream", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"] + - ["google::protobuf", "MessageLite", True, "ParsePartialFromCodedStream", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"] + - ["google::protobuf", "MessageLite", True, "MergeFromCodedStream", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"] + - ["google::protobuf", "MessageLite", True, "MergePartialFromCodedStream", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"] + + # Serialization into an output buffer/stream: the message (`this`) taints `Argument[*0]`. + - ["google::protobuf", "MessageLite", True, "SerializeToString", "", "", "Argument[-1]", "Argument[*0]", "taint", "manual"] + - ["google::protobuf", "MessageLite", True, "SerializePartialToString", "", "", "Argument[-1]", "Argument[*0]", "taint", "manual"] + - ["google::protobuf", "MessageLite", True, "AppendToString", "", "", "Argument[-1]", "Argument[*0]", "taint", "manual"] + - ["google::protobuf", "MessageLite", True, "AppendPartialToString", "", "", "Argument[-1]", "Argument[*0]", "taint", "manual"] + - ["google::protobuf", "MessageLite", True, "SerializeToArray", "", "", "Argument[-1]", "Argument[*0]", "taint", "manual"] + - ["google::protobuf", "MessageLite", True, "SerializePartialToArray", "", "", "Argument[-1]", "Argument[*0]", "taint", "manual"] + - ["google::protobuf", "MessageLite", True, "SerializeToCord", "", "", "Argument[-1]", "Argument[*0]", "taint", "manual"] + - ["google::protobuf", "MessageLite", True, "SerializePartialToCord", "", "", "Argument[-1]", "Argument[*0]", "taint", "manual"] + - ["google::protobuf", "MessageLite", True, "AppendToCord", "", "", "Argument[-1]", "Argument[*0]", "taint", "manual"] + - ["google::protobuf", "MessageLite", True, "AppendPartialToCord", "", "", "Argument[-1]", "Argument[*0]", "taint", "manual"] + - ["google::protobuf", "MessageLite", True, "SerializeToOstream", "", "", "Argument[-1]", "Argument[*0]", "taint", "manual"] + - ["google::protobuf", "MessageLite", True, "SerializePartialToOstream", "", "", "Argument[-1]", "Argument[*0]", "taint", "manual"] + - ["google::protobuf", "MessageLite", True, "SerializeToZeroCopyStream", "", "", "Argument[-1]", "Argument[*0]", "taint", "manual"] + - ["google::protobuf", "MessageLite", True, "SerializePartialToZeroCopyStream", "", "", "Argument[-1]", "Argument[*0]", "taint", "manual"] + - ["google::protobuf", "MessageLite", True, "SerializeToCodedStream", "", "", "Argument[-1]", "Argument[*0]", "taint", "manual"] + - ["google::protobuf", "MessageLite", True, "SerializePartialToCodedStream", "", "", "Argument[-1]", "Argument[*0]", "taint", "manual"] + + # Serialization returning the bytes: the message (`this`) taints the (by-value) return value. + - ["google::protobuf", "MessageLite", True, "SerializeAsString", "", "", "Argument[-1]", "ReturnValue", "taint", "manual"] + - ["google::protobuf", "MessageLite", True, "SerializePartialAsString", "", "", "Argument[-1]", "ReturnValue", "taint", "manual"] + - ["google::protobuf", "MessageLite", True, "SerializeAsCord", "", "", "Argument[-1]", "ReturnValue", "taint", "manual"] + - ["google::protobuf", "MessageLite", True, "SerializePartialAsCord", "", "", "Argument[-1]", "ReturnValue", "taint", "manual"] diff --git a/cpp/ql/test/library-tests/dataflow/external-models/flow.expected b/cpp/ql/test/library-tests/dataflow/external-models/flow.expected index b6f5f4a4452f..5409656f7e57 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/flow.expected +++ b/cpp/ql/test/library-tests/dataflow/external-models/flow.expected @@ -96,6 +96,10 @@ models | 95 | Summary: Azure::Core::IO; BodyStream; true; ReadToEnd; ; ; Argument[-1]; ReturnValue.Element; taint; manual | | 96 | Summary: Azure; Nullable; true; Value; ; ; Argument[-1]; ReturnValue[*]; taint; manual | | 97 | Summary: boost::asio; ; false; buffer; ; ; Argument[*0]; ReturnValue; taint; manual | +| 98 | Summary: google::protobuf; MessageLite; true; ParseFromArray; ; ; Argument[*0]; Argument[-1]; taint; manual | +| 99 | Summary: google::protobuf; MessageLite; true; ParseFromString; ; ; Argument[*0]; Argument[-1]; taint; manual | +| 100 | Summary: google::protobuf; MessageLite; true; SerializeAsString; ; ; Argument[-1]; ReturnValue; taint; manual | +| 101 | Summary: google::protobuf; MessageLite; true; SerializeToArray; ; ; Argument[-1]; Argument[*0]; taint; manual | edges | asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:91:7:91:17 | recv_buffer | provenance | Src:MaD:56 | | asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:93:29:93:39 | recv_buffer | provenance | Src:MaD:56 Sink:MaD:4 | @@ -144,6 +148,26 @@ edges | azure.cpp:294:38:294:53 | call to operator[] | azure.cpp:295:10:295:20 | contentType | provenance | | | azure.cpp:294:38:294:53 | call to operator[] | azure.cpp:295:10:295:20 | contentType | provenance | | | azure.cpp:295:10:295:20 | contentType | azure.cpp:295:10:295:20 | contentType | provenance | | +| protobuf.cpp:75:33:75:40 | call to source | protobuf.cpp:76:22:76:25 | *data | provenance | TaintFunction | +| protobuf.cpp:76:2:76:4 | ParseFromString output argument | protobuf.cpp:78:2:78:4 | *msg | provenance | | +| protobuf.cpp:76:22:76:25 | *data | protobuf.cpp:76:2:76:4 | ParseFromString output argument | provenance | MaD:99 | +| protobuf.cpp:78:2:78:4 | *msg | protobuf.cpp:78:23:78:25 | SerializeToArray output argument | provenance | MaD:101 | +| protobuf.cpp:78:23:78:25 | SerializeToArray output argument | protobuf.cpp:79:7:79:10 | * ... | provenance | | +| protobuf.cpp:84:33:84:40 | call to source | protobuf.cpp:85:21:85:31 | *call to data | provenance | TaintFunction | +| protobuf.cpp:85:2:85:4 | ParseFromArray output argument | protobuf.cpp:87:2:87:4 | *msg | provenance | | +| protobuf.cpp:85:21:85:31 | *call to data | protobuf.cpp:85:2:85:4 | ParseFromArray output argument | provenance | MaD:98 | +| protobuf.cpp:87:2:87:4 | *msg | protobuf.cpp:87:23:87:25 | SerializeToArray output argument | provenance | MaD:101 | +| protobuf.cpp:87:23:87:25 | SerializeToArray output argument | protobuf.cpp:88:7:88:10 | * ... | provenance | | +| protobuf.cpp:95:33:95:40 | call to source | protobuf.cpp:96:22:96:25 | *data | provenance | TaintFunction | +| protobuf.cpp:96:2:96:4 | ParseFromString output argument | protobuf.cpp:98:23:98:25 | *msg | provenance | | +| protobuf.cpp:96:22:96:25 | *data | protobuf.cpp:96:2:96:4 | ParseFromString output argument | provenance | MaD:99 | +| protobuf.cpp:98:2:98:5 | ParseFromString output argument | protobuf.cpp:100:2:100:5 | *msg2 | provenance | | +| protobuf.cpp:98:23:98:25 | *msg | protobuf.cpp:98:27:98:43 | call to SerializeAsString | provenance | MaD:100 | +| protobuf.cpp:98:23:98:45 | call to SerializeAsString | protobuf.cpp:98:2:98:5 | ParseFromString output argument | provenance | MaD:99 | +| protobuf.cpp:98:27:98:43 | call to SerializeAsString | protobuf.cpp:98:23:98:45 | call to SerializeAsString | provenance | | +| protobuf.cpp:98:27:98:43 | call to SerializeAsString | protobuf.cpp:98:27:98:43 | call to SerializeAsString | provenance | | +| protobuf.cpp:100:2:100:5 | *msg2 | protobuf.cpp:100:24:100:26 | SerializeToArray output argument | provenance | MaD:101 | +| protobuf.cpp:100:24:100:26 | SerializeToArray output argument | protobuf.cpp:101:7:101:10 | * ... | provenance | | | test.cpp:7:47:7:52 | value2 | test.cpp:7:64:7:69 | value2 | provenance | | | test.cpp:7:64:7:69 | value2 | test.cpp:7:5:7:30 | *ymlStepGenerated_with_body | provenance | | | test.cpp:10:10:10:18 | call to ymlSource | test.cpp:10:10:10:18 | call to ymlSource | provenance | Src:MaD:48 | @@ -532,6 +556,29 @@ nodes | azure.cpp:295:10:295:20 | contentType | semmle.label | contentType | | azure.cpp:295:10:295:20 | contentType | semmle.label | contentType | | azure.cpp:295:10:295:20 | contentType | semmle.label | contentType | +| protobuf.cpp:75:33:75:40 | call to source | semmle.label | call to source | +| protobuf.cpp:76:2:76:4 | ParseFromString output argument | semmle.label | ParseFromString output argument | +| protobuf.cpp:76:22:76:25 | *data | semmle.label | *data | +| protobuf.cpp:78:2:78:4 | *msg | semmle.label | *msg | +| protobuf.cpp:78:23:78:25 | SerializeToArray output argument | semmle.label | SerializeToArray output argument | +| protobuf.cpp:79:7:79:10 | * ... | semmle.label | * ... | +| protobuf.cpp:84:33:84:40 | call to source | semmle.label | call to source | +| protobuf.cpp:85:2:85:4 | ParseFromArray output argument | semmle.label | ParseFromArray output argument | +| protobuf.cpp:85:21:85:31 | *call to data | semmle.label | *call to data | +| protobuf.cpp:87:2:87:4 | *msg | semmle.label | *msg | +| protobuf.cpp:87:23:87:25 | SerializeToArray output argument | semmle.label | SerializeToArray output argument | +| protobuf.cpp:88:7:88:10 | * ... | semmle.label | * ... | +| protobuf.cpp:95:33:95:40 | call to source | semmle.label | call to source | +| protobuf.cpp:96:2:96:4 | ParseFromString output argument | semmle.label | ParseFromString output argument | +| protobuf.cpp:96:22:96:25 | *data | semmle.label | *data | +| protobuf.cpp:98:2:98:5 | ParseFromString output argument | semmle.label | ParseFromString output argument | +| protobuf.cpp:98:23:98:25 | *msg | semmle.label | *msg | +| protobuf.cpp:98:23:98:45 | call to SerializeAsString | semmle.label | call to SerializeAsString | +| protobuf.cpp:98:27:98:43 | call to SerializeAsString | semmle.label | call to SerializeAsString | +| protobuf.cpp:98:27:98:43 | call to SerializeAsString | semmle.label | call to SerializeAsString | +| protobuf.cpp:100:2:100:5 | *msg2 | semmle.label | *msg2 | +| protobuf.cpp:100:24:100:26 | SerializeToArray output argument | semmle.label | SerializeToArray output argument | +| protobuf.cpp:101:7:101:10 | * ... | semmle.label | * ... | | test.cpp:7:5:7:30 | *ymlStepGenerated_with_body | semmle.label | *ymlStepGenerated_with_body | | test.cpp:7:47:7:52 | value2 | semmle.label | value2 | | test.cpp:7:64:7:69 | value2 | semmle.label | value2 | diff --git a/cpp/ql/test/library-tests/dataflow/external-models/protobuf.cpp b/cpp/ql/test/library-tests/dataflow/external-models/protobuf.cpp new file mode 100644 index 000000000000..f7bb22a4855b --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/external-models/protobuf.cpp @@ -0,0 +1,122 @@ + +// --- stub library headers --- + +namespace std { + typedef unsigned long size_t; + + template class allocator { + }; + + template struct char_traits { + }; + + template, class Allocator = allocator > + class basic_string { + public: + basic_string(); + basic_string(const charT* s, const Allocator& a = Allocator()); + const charT* data() const; + size_t size() const; + }; + + typedef basic_string string; + + class istream { + public: + istream(); + }; + + class ostream { + public: + ostream(); + }; +} + +namespace google { +namespace protobuf { + // A faithful subset of `MessageLite`; every method below is declared on `MessageLite` + // in the real headers (message_lite.h), including the iostream-based ones. + class MessageLite { + public: + bool ParseFromString(const std::string &data); + bool MergeFromString(const std::string &data); + bool ParsePartialFromString(const std::string &data); + bool ParseFromArray(const void *data, int size); + bool ParseFromIstream(std::istream *input); + bool SerializeToString(std::string *output) const; + bool SerializePartialToString(std::string *output) const; + bool AppendToString(std::string *output) const; + bool SerializeToArray(void *data, int size) const; + bool SerializeToOstream(std::ostream *output) const; + std::string SerializeAsString() const; + }; + + class Message : public MessageLite { + }; +} +} + +// A generated message type derives from `Message`. +class Person : public google::protobuf::Message { +}; + +// --- test code --- + +char *source(); +void sink(char); + +// Message taint is observed through `SerializeToArray`, whose scalar output flows cleanly +// to a sink. The object-typed serialize outputs (String/Ostream/...) and the input-stream +// parse methods are checked directly by `steps.ql`, which asserts each summary step exists. + +// Deserialization: the encoded input taints the message (`this`). +void test_ParseFromString() { + Person msg; + std::string data = std::string(source()); + msg.ParseFromString(data); + char buf[64]; + msg.SerializeToArray(buf, sizeof(buf)); + sink(*buf); // $ ir +} + +void test_ParseFromArray() { + Person msg; + std::string data = std::string(source()); + msg.ParseFromArray(data.data(), data.size()); + char buf[64]; + msg.SerializeToArray(buf, sizeof(buf)); + sink(*buf); // $ ir +} + +// Serialization returning the bytes: the message taints the returned string, observed by +// parsing it into a second message and serializing that back out. +void test_SerializeAsString() { + Person msg; + std::string data = std::string(source()); + msg.ParseFromString(data); + Person msg2; + msg2.ParseFromString(msg.SerializeAsString()); + char buf[64]; + msg2.SerializeToArray(buf, sizeof(buf)); + sink(*buf); // $ ir +} + +// Additional modeled methods, exercised so their summary steps are covered by `steps.ql`. +void test_step_coverage() { + Person msg; + std::string data = std::string(source()); + + msg.MergeFromString(data); + msg.ParsePartialFromString(data); + + std::istream in; + msg.ParseFromIstream(&in); + + std::string out; + msg.SerializeToString(&out); + msg.SerializePartialToString(&out); + msg.AppendToString(&out); + + std::ostream os; + msg.SerializeToOstream(&os); +} diff --git a/cpp/ql/test/library-tests/dataflow/external-models/steps.expected b/cpp/ql/test/library-tests/dataflow/external-models/steps.expected index 0fe13460cfbf..a1cfc6e1c3d9 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/steps.expected +++ b/cpp/ql/test/library-tests/dataflow/external-models/steps.expected @@ -4,6 +4,21 @@ | azure.cpp:262:5:262:8 | *resp | azure.cpp:262:23:262:28 | ReadToCount output argument | | azure.cpp:287:79:287:98 | call to string | azure.cpp:287:62:287:99 | call to Url | | azure.cpp:289:24:289:56 | call to GetHeader | azure.cpp:289:63:289:65 | call to Value | +| protobuf.cpp:76:22:76:25 | *data | protobuf.cpp:76:2:76:4 | ParseFromString output argument | +| protobuf.cpp:78:2:78:4 | *msg | protobuf.cpp:78:23:78:25 | SerializeToArray output argument | +| protobuf.cpp:85:21:85:31 | *call to data | protobuf.cpp:85:2:85:4 | ParseFromArray output argument | +| protobuf.cpp:87:2:87:4 | *msg | protobuf.cpp:87:23:87:25 | SerializeToArray output argument | +| protobuf.cpp:96:22:96:25 | *data | protobuf.cpp:96:2:96:4 | ParseFromString output argument | +| protobuf.cpp:98:23:98:25 | *msg | protobuf.cpp:98:27:98:43 | call to SerializeAsString | +| protobuf.cpp:98:23:98:45 | call to SerializeAsString | protobuf.cpp:98:2:98:5 | ParseFromString output argument | +| protobuf.cpp:100:2:100:5 | *msg2 | protobuf.cpp:100:24:100:26 | SerializeToArray output argument | +| protobuf.cpp:109:22:109:25 | *data | protobuf.cpp:109:2:109:4 | MergeFromString output argument | +| protobuf.cpp:110:29:110:32 | *data | protobuf.cpp:110:2:110:4 | ParsePartialFromString output argument | +| protobuf.cpp:113:23:113:25 | *& ... | protobuf.cpp:113:2:113:4 | ParseFromIstream output argument | +| protobuf.cpp:116:2:116:4 | *msg | protobuf.cpp:116:24:116:27 | SerializeToString output argument | +| protobuf.cpp:117:2:117:4 | *msg | protobuf.cpp:117:31:117:34 | SerializePartialToString output argument | +| protobuf.cpp:118:2:118:4 | *msg | protobuf.cpp:118:21:118:24 | AppendToString output argument | +| protobuf.cpp:121:2:121:4 | *msg | protobuf.cpp:121:25:121:27 | SerializeToOstream output argument | | test.cpp:17:24:17:24 | x | test.cpp:17:10:17:22 | call to ymlStepManual | | test.cpp:21:27:21:27 | x | test.cpp:21:10:21:25 | call to ymlStepGenerated | | test.cpp:25:35:25:35 | x | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | From 5f0b3dff8c28721a879e8fb97166a913e9279243 Mon Sep 17 00:00:00 2001 From: Akshay K Date: Fri, 28 Aug 2026 12:28:40 -0400 Subject: [PATCH 2/3] Update cpp/ql/lib/change-notes/2026-08-27-protobuf-models.md Co-authored-by: Jeroen Ketema <93738568+jketema@users.noreply.github.com> --- cpp/ql/lib/change-notes/2026-08-27-protobuf-models.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/lib/change-notes/2026-08-27-protobuf-models.md b/cpp/ql/lib/change-notes/2026-08-27-protobuf-models.md index a039b28de676..f68eaac98cfc 100644 --- a/cpp/ql/lib/change-notes/2026-08-27-protobuf-models.md +++ b/cpp/ql/lib/change-notes/2026-08-27-protobuf-models.md @@ -1,4 +1,4 @@ --- category: minorAnalysis --- -* Added flow summaries for the Protocol Buffers C++ API (`google::protobuf::MessageLite`, covering `Message` and all generated messages). The `ParseFrom*`/`MergeFrom*` methods (string, array, Cord, istream, and zero-copy/coded-stream forms) propagate taint from the encoded input to the message, and the `SerializeTo*`/`SerializeAs*`/`AppendTo*` methods propagate taint from the message to the output buffer, stream, or return value. +* Added flow summaries for the Protocol Buffers C++ API (`google::protobuf::MessageLite`, covering `Message` and all generated messages). From d0b3dd50b911d1682d2c3b0fbe02c41d5c5cbf2b Mon Sep 17 00:00:00 2001 From: AkshayK Date: Fri, 28 Aug 2026 13:14:39 -0400 Subject: [PATCH 3/3] fix(cpp): correct protobuf string parse models and expand test coverage --- cpp/ql/lib/ext/Protobuf.model.yml | 17 +- .../dataflow/external-models/flow.expected | 80 ++++----- .../dataflow/external-models/protobuf.cpp | 160 +++++++++++++++--- .../dataflow/external-models/steps.expected | 65 +++++-- .../external-models/validatemodels.expected | 1 + 5 files changed, 233 insertions(+), 90 deletions(-) diff --git a/cpp/ql/lib/ext/Protobuf.model.yml b/cpp/ql/lib/ext/Protobuf.model.yml index b080855536a1..08171f22e298 100644 --- a/cpp/ql/lib/ext/Protobuf.model.yml +++ b/cpp/ql/lib/ext/Protobuf.model.yml @@ -9,11 +9,18 @@ extensions: # File-descriptor variants (`{Parse,Serialize}*FromFileDescriptor`) are intentionally omitted: # the descriptor is an `int`, not a data buffer, so there is no buffer argument to model. - # Deserialization: the encoded input (`Argument[*0]`) taints the message (`this`). - - ["google::protobuf", "MessageLite", True, "ParseFromString", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"] - - ["google::protobuf", "MessageLite", True, "ParsePartialFromString", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"] - - ["google::protobuf", "MessageLite", True, "MergeFromString", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"] - - ["google::protobuf", "MessageLite", True, "MergePartialFromString", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"] + # Deserialization: the encoded input taints the message (`this`). The `*FromString` methods each + # have a `string_view` overload (the buffer is the by-value argument, so `Argument[0]`) and a + # `const Cord &` overload (the buffer is behind a reference, so `Argument[*0]`). The remaining + # inputs below are pointers or references, so they take `Argument[*0]`. + - ["google::protobuf", "MessageLite", True, "ParseFromString", "(string_view)", "", "Argument[0]", "Argument[-1]", "taint", "manual"] + - ["google::protobuf", "MessageLite", True, "ParseFromString", "(const Cord &)", "", "Argument[*0]", "Argument[-1]", "taint", "manual"] + - ["google::protobuf", "MessageLite", True, "ParsePartialFromString", "(string_view)", "", "Argument[0]", "Argument[-1]", "taint", "manual"] + - ["google::protobuf", "MessageLite", True, "ParsePartialFromString", "(const Cord &)", "", "Argument[*0]", "Argument[-1]", "taint", "manual"] + - ["google::protobuf", "MessageLite", True, "MergeFromString", "(string_view)", "", "Argument[0]", "Argument[-1]", "taint", "manual"] + - ["google::protobuf", "MessageLite", True, "MergeFromString", "(const Cord &)", "", "Argument[*0]", "Argument[-1]", "taint", "manual"] + - ["google::protobuf", "MessageLite", True, "MergePartialFromString", "(string_view)", "", "Argument[0]", "Argument[-1]", "taint", "manual"] + - ["google::protobuf", "MessageLite", True, "MergePartialFromString", "(const Cord &)", "", "Argument[*0]", "Argument[-1]", "taint", "manual"] - ["google::protobuf", "MessageLite", True, "ParseFromArray", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"] - ["google::protobuf", "MessageLite", True, "ParsePartialFromArray", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"] - ["google::protobuf", "MessageLite", True, "ParseFromCord", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"] diff --git a/cpp/ql/test/library-tests/dataflow/external-models/flow.expected b/cpp/ql/test/library-tests/dataflow/external-models/flow.expected index 5409656f7e57..d51464ea7f5b 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/flow.expected +++ b/cpp/ql/test/library-tests/dataflow/external-models/flow.expected @@ -97,9 +97,8 @@ models | 96 | Summary: Azure; Nullable; true; Value; ; ; Argument[-1]; ReturnValue[*]; taint; manual | | 97 | Summary: boost::asio; ; false; buffer; ; ; Argument[*0]; ReturnValue; taint; manual | | 98 | Summary: google::protobuf; MessageLite; true; ParseFromArray; ; ; Argument[*0]; Argument[-1]; taint; manual | -| 99 | Summary: google::protobuf; MessageLite; true; ParseFromString; ; ; Argument[*0]; Argument[-1]; taint; manual | -| 100 | Summary: google::protobuf; MessageLite; true; SerializeAsString; ; ; Argument[-1]; ReturnValue; taint; manual | -| 101 | Summary: google::protobuf; MessageLite; true; SerializeToArray; ; ; Argument[-1]; Argument[*0]; taint; manual | +| 99 | Summary: google::protobuf; MessageLite; true; SerializeAsString; ; ; Argument[-1]; ReturnValue; taint; manual | +| 100 | Summary: google::protobuf; MessageLite; true; SerializeToArray; ; ; Argument[-1]; Argument[*0]; taint; manual | edges | asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:91:7:91:17 | recv_buffer | provenance | Src:MaD:56 | | asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:93:29:93:39 | recv_buffer | provenance | Src:MaD:56 Sink:MaD:4 | @@ -148,26 +147,21 @@ edges | azure.cpp:294:38:294:53 | call to operator[] | azure.cpp:295:10:295:20 | contentType | provenance | | | azure.cpp:294:38:294:53 | call to operator[] | azure.cpp:295:10:295:20 | contentType | provenance | | | azure.cpp:295:10:295:20 | contentType | azure.cpp:295:10:295:20 | contentType | provenance | | -| protobuf.cpp:75:33:75:40 | call to source | protobuf.cpp:76:22:76:25 | *data | provenance | TaintFunction | -| protobuf.cpp:76:2:76:4 | ParseFromString output argument | protobuf.cpp:78:2:78:4 | *msg | provenance | | -| protobuf.cpp:76:22:76:25 | *data | protobuf.cpp:76:2:76:4 | ParseFromString output argument | provenance | MaD:99 | -| protobuf.cpp:78:2:78:4 | *msg | protobuf.cpp:78:23:78:25 | SerializeToArray output argument | provenance | MaD:101 | -| protobuf.cpp:78:23:78:25 | SerializeToArray output argument | protobuf.cpp:79:7:79:10 | * ... | provenance | | -| protobuf.cpp:84:33:84:40 | call to source | protobuf.cpp:85:21:85:31 | *call to data | provenance | TaintFunction | -| protobuf.cpp:85:2:85:4 | ParseFromArray output argument | protobuf.cpp:87:2:87:4 | *msg | provenance | | -| protobuf.cpp:85:21:85:31 | *call to data | protobuf.cpp:85:2:85:4 | ParseFromArray output argument | provenance | MaD:98 | -| protobuf.cpp:87:2:87:4 | *msg | protobuf.cpp:87:23:87:25 | SerializeToArray output argument | provenance | MaD:101 | -| protobuf.cpp:87:23:87:25 | SerializeToArray output argument | protobuf.cpp:88:7:88:10 | * ... | provenance | | -| protobuf.cpp:95:33:95:40 | call to source | protobuf.cpp:96:22:96:25 | *data | provenance | TaintFunction | -| protobuf.cpp:96:2:96:4 | ParseFromString output argument | protobuf.cpp:98:23:98:25 | *msg | provenance | | -| protobuf.cpp:96:22:96:25 | *data | protobuf.cpp:96:2:96:4 | ParseFromString output argument | provenance | MaD:99 | -| protobuf.cpp:98:2:98:5 | ParseFromString output argument | protobuf.cpp:100:2:100:5 | *msg2 | provenance | | -| protobuf.cpp:98:23:98:25 | *msg | protobuf.cpp:98:27:98:43 | call to SerializeAsString | provenance | MaD:100 | -| protobuf.cpp:98:23:98:45 | call to SerializeAsString | protobuf.cpp:98:2:98:5 | ParseFromString output argument | provenance | MaD:99 | -| protobuf.cpp:98:27:98:43 | call to SerializeAsString | protobuf.cpp:98:23:98:45 | call to SerializeAsString | provenance | | -| protobuf.cpp:98:27:98:43 | call to SerializeAsString | protobuf.cpp:98:27:98:43 | call to SerializeAsString | provenance | | -| protobuf.cpp:100:2:100:5 | *msg2 | protobuf.cpp:100:24:100:26 | SerializeToArray output argument | provenance | MaD:101 | -| protobuf.cpp:100:24:100:26 | SerializeToArray output argument | protobuf.cpp:101:7:101:10 | * ... | provenance | | +| protobuf.cpp:140:33:140:40 | call to source | protobuf.cpp:141:21:141:31 | *call to data | provenance | TaintFunction | +| protobuf.cpp:141:2:141:4 | ParseFromArray output argument | protobuf.cpp:143:2:143:4 | *msg | provenance | | +| protobuf.cpp:141:21:141:31 | *call to data | protobuf.cpp:141:2:141:4 | ParseFromArray output argument | provenance | MaD:98 | +| protobuf.cpp:143:2:143:4 | *msg | protobuf.cpp:143:23:143:25 | SerializeToArray output argument | provenance | MaD:100 | +| protobuf.cpp:143:23:143:25 | SerializeToArray output argument | protobuf.cpp:144:7:144:10 | * ... | provenance | | +| protobuf.cpp:151:33:151:40 | call to source | protobuf.cpp:152:21:152:31 | *call to data | provenance | TaintFunction | +| protobuf.cpp:152:2:152:4 | ParseFromArray output argument | protobuf.cpp:153:18:153:20 | *msg | provenance | | +| protobuf.cpp:152:21:152:31 | *call to data | protobuf.cpp:152:2:152:4 | ParseFromArray output argument | provenance | MaD:98 | +| protobuf.cpp:153:18:153:20 | *msg | protobuf.cpp:153:22:153:38 | call to SerializeAsString | provenance | MaD:99 | +| protobuf.cpp:153:22:153:38 | call to SerializeAsString | protobuf.cpp:153:22:153:38 | call to SerializeAsString | provenance | | +| protobuf.cpp:153:22:153:38 | call to SerializeAsString | protobuf.cpp:155:22:155:29 | *call to data | provenance | TaintFunction | +| protobuf.cpp:155:2:155:5 | ParseFromArray output argument | protobuf.cpp:157:2:157:5 | *msg2 | provenance | | +| protobuf.cpp:155:22:155:29 | *call to data | protobuf.cpp:155:2:155:5 | ParseFromArray output argument | provenance | MaD:98 | +| protobuf.cpp:157:2:157:5 | *msg2 | protobuf.cpp:157:24:157:26 | SerializeToArray output argument | provenance | MaD:100 | +| protobuf.cpp:157:24:157:26 | SerializeToArray output argument | protobuf.cpp:158:7:158:10 | * ... | provenance | | | test.cpp:7:47:7:52 | value2 | test.cpp:7:64:7:69 | value2 | provenance | | | test.cpp:7:64:7:69 | value2 | test.cpp:7:5:7:30 | *ymlStepGenerated_with_body | provenance | | | test.cpp:10:10:10:18 | call to ymlSource | test.cpp:10:10:10:18 | call to ymlSource | provenance | Src:MaD:48 | @@ -556,29 +550,23 @@ nodes | azure.cpp:295:10:295:20 | contentType | semmle.label | contentType | | azure.cpp:295:10:295:20 | contentType | semmle.label | contentType | | azure.cpp:295:10:295:20 | contentType | semmle.label | contentType | -| protobuf.cpp:75:33:75:40 | call to source | semmle.label | call to source | -| protobuf.cpp:76:2:76:4 | ParseFromString output argument | semmle.label | ParseFromString output argument | -| protobuf.cpp:76:22:76:25 | *data | semmle.label | *data | -| protobuf.cpp:78:2:78:4 | *msg | semmle.label | *msg | -| protobuf.cpp:78:23:78:25 | SerializeToArray output argument | semmle.label | SerializeToArray output argument | -| protobuf.cpp:79:7:79:10 | * ... | semmle.label | * ... | -| protobuf.cpp:84:33:84:40 | call to source | semmle.label | call to source | -| protobuf.cpp:85:2:85:4 | ParseFromArray output argument | semmle.label | ParseFromArray output argument | -| protobuf.cpp:85:21:85:31 | *call to data | semmle.label | *call to data | -| protobuf.cpp:87:2:87:4 | *msg | semmle.label | *msg | -| protobuf.cpp:87:23:87:25 | SerializeToArray output argument | semmle.label | SerializeToArray output argument | -| protobuf.cpp:88:7:88:10 | * ... | semmle.label | * ... | -| protobuf.cpp:95:33:95:40 | call to source | semmle.label | call to source | -| protobuf.cpp:96:2:96:4 | ParseFromString output argument | semmle.label | ParseFromString output argument | -| protobuf.cpp:96:22:96:25 | *data | semmle.label | *data | -| protobuf.cpp:98:2:98:5 | ParseFromString output argument | semmle.label | ParseFromString output argument | -| protobuf.cpp:98:23:98:25 | *msg | semmle.label | *msg | -| protobuf.cpp:98:23:98:45 | call to SerializeAsString | semmle.label | call to SerializeAsString | -| protobuf.cpp:98:27:98:43 | call to SerializeAsString | semmle.label | call to SerializeAsString | -| protobuf.cpp:98:27:98:43 | call to SerializeAsString | semmle.label | call to SerializeAsString | -| protobuf.cpp:100:2:100:5 | *msg2 | semmle.label | *msg2 | -| protobuf.cpp:100:24:100:26 | SerializeToArray output argument | semmle.label | SerializeToArray output argument | -| protobuf.cpp:101:7:101:10 | * ... | semmle.label | * ... | +| protobuf.cpp:140:33:140:40 | call to source | semmle.label | call to source | +| protobuf.cpp:141:2:141:4 | ParseFromArray output argument | semmle.label | ParseFromArray output argument | +| protobuf.cpp:141:21:141:31 | *call to data | semmle.label | *call to data | +| protobuf.cpp:143:2:143:4 | *msg | semmle.label | *msg | +| protobuf.cpp:143:23:143:25 | SerializeToArray output argument | semmle.label | SerializeToArray output argument | +| protobuf.cpp:144:7:144:10 | * ... | semmle.label | * ... | +| protobuf.cpp:151:33:151:40 | call to source | semmle.label | call to source | +| protobuf.cpp:152:2:152:4 | ParseFromArray output argument | semmle.label | ParseFromArray output argument | +| protobuf.cpp:152:21:152:31 | *call to data | semmle.label | *call to data | +| protobuf.cpp:153:18:153:20 | *msg | semmle.label | *msg | +| protobuf.cpp:153:22:153:38 | call to SerializeAsString | semmle.label | call to SerializeAsString | +| protobuf.cpp:153:22:153:38 | call to SerializeAsString | semmle.label | call to SerializeAsString | +| protobuf.cpp:155:2:155:5 | ParseFromArray output argument | semmle.label | ParseFromArray output argument | +| protobuf.cpp:155:22:155:29 | *call to data | semmle.label | *call to data | +| protobuf.cpp:157:2:157:5 | *msg2 | semmle.label | *msg2 | +| protobuf.cpp:157:24:157:26 | SerializeToArray output argument | semmle.label | SerializeToArray output argument | +| protobuf.cpp:158:7:158:10 | * ... | semmle.label | * ... | | test.cpp:7:5:7:30 | *ymlStepGenerated_with_body | semmle.label | *ymlStepGenerated_with_body | | test.cpp:7:47:7:52 | value2 | semmle.label | value2 | | test.cpp:7:64:7:69 | value2 | semmle.label | value2 | diff --git a/cpp/ql/test/library-tests/dataflow/external-models/protobuf.cpp b/cpp/ql/test/library-tests/dataflow/external-models/protobuf.cpp index f7bb22a4855b..bc9a29ce45a0 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/protobuf.cpp +++ b/cpp/ql/test/library-tests/dataflow/external-models/protobuf.cpp @@ -32,23 +32,86 @@ namespace std { }; } +namespace absl { + // `absl::string_view` is passed by value; `absl::Cord` is passed by const reference. + class string_view { + public: + string_view(); + string_view(const char *s); + string_view(const std::string &s); + }; + + class Cord { + public: + Cord(); + }; +} + namespace google { namespace protobuf { - // A faithful subset of `MessageLite`; every method below is declared on `MessageLite` - // in the real headers (message_lite.h), including the iostream-based ones. + namespace io { + class ZeroCopyInputStream {}; + class ZeroCopyOutputStream {}; + class CodedInputStream {}; + class CodedOutputStream {}; + } + + // A faithful subset of `MessageLite`. The string/Cord/stream signatures mirror the real + // `message_lite.h`; the iostream-based methods are declared on `Message` in the real headers + // but are modeled here on `MessageLite` (with `subtypes` covering `Message`). class MessageLite { public: - bool ParseFromString(const std::string &data); - bool MergeFromString(const std::string &data); - bool ParsePartialFromString(const std::string &data); + // Deserialization: input taints the message. + bool ParseFromString(absl::string_view data); + bool ParseFromString(const absl::Cord &data); + bool ParsePartialFromString(absl::string_view data); + bool ParsePartialFromString(const absl::Cord &data); + bool MergeFromString(absl::string_view data); + bool MergeFromString(const absl::Cord &data); + bool MergePartialFromString(absl::string_view data); + bool MergePartialFromString(const absl::Cord &data); bool ParseFromArray(const void *data, int size); + bool ParsePartialFromArray(const void *data, int size); + bool ParseFromCord(const absl::Cord &data); + bool ParsePartialFromCord(const absl::Cord &data); + bool MergeFromCord(const absl::Cord &data); + bool MergePartialFromCord(const absl::Cord &data); bool ParseFromIstream(std::istream *input); + bool ParsePartialFromIstream(std::istream *input); + bool ParseFromZeroCopyStream(io::ZeroCopyInputStream *input); + bool ParsePartialFromZeroCopyStream(io::ZeroCopyInputStream *input); + bool ParseFromBoundedZeroCopyStream(io::ZeroCopyInputStream *input, int size); + bool ParsePartialFromBoundedZeroCopyStream(io::ZeroCopyInputStream *input, int size); + bool MergeFromBoundedZeroCopyStream(io::ZeroCopyInputStream *input, int size); + bool MergePartialFromBoundedZeroCopyStream(io::ZeroCopyInputStream *input, int size); + bool ParseFromCodedStream(io::CodedInputStream *input); + bool ParsePartialFromCodedStream(io::CodedInputStream *input); + bool MergeFromCodedStream(io::CodedInputStream *input); + bool MergePartialFromCodedStream(io::CodedInputStream *input); + + // Serialization into an output buffer/stream: the message taints the output argument. bool SerializeToString(std::string *output) const; bool SerializePartialToString(std::string *output) const; bool AppendToString(std::string *output) const; + bool AppendPartialToString(std::string *output) const; bool SerializeToArray(void *data, int size) const; + bool SerializePartialToArray(void *data, int size) const; + bool SerializeToCord(absl::Cord *output) const; + bool SerializePartialToCord(absl::Cord *output) const; + bool AppendToCord(absl::Cord *output) const; + bool AppendPartialToCord(absl::Cord *output) const; bool SerializeToOstream(std::ostream *output) const; + bool SerializePartialToOstream(std::ostream *output) const; + bool SerializeToZeroCopyStream(io::ZeroCopyOutputStream *output) const; + bool SerializePartialToZeroCopyStream(io::ZeroCopyOutputStream *output) const; + bool SerializeToCodedStream(io::CodedOutputStream *output) const; + bool SerializePartialToCodedStream(io::CodedOutputStream *output) const; + + // Serialization returning the bytes. std::string SerializeAsString() const; + std::string SerializePartialAsString() const; + absl::Cord SerializeAsCord() const; + absl::Cord SerializePartialAsCord() const; }; class Message : public MessageLite { @@ -65,20 +128,13 @@ class Person : public google::protobuf::Message { char *source(); void sink(char); -// Message taint is observed through `SerializeToArray`, whose scalar output flows cleanly -// to a sink. The object-typed serialize outputs (String/Ostream/...) and the input-stream -// parse methods are checked directly by `steps.ql`, which asserts each summary step exists. +// End-to-end flow is demonstrated through the pointer-to-buffer methods, where content taint +// flows naturally: `ParseFromArray` reads a tainted buffer into the message, and `SerializeToArray` +// writes the message back out to a scalar buffer that reaches the sink. The `string_view`, `Cord`, +// and stream overloads do not carry content taint through their argument conversions without further +// library models, so they are exercised for summary-step coverage (`steps.ql`) rather than flow. // Deserialization: the encoded input taints the message (`this`). -void test_ParseFromString() { - Person msg; - std::string data = std::string(source()); - msg.ParseFromString(data); - char buf[64]; - msg.SerializeToArray(buf, sizeof(buf)); - sink(*buf); // $ ir -} - void test_ParseFromArray() { Person msg; std::string data = std::string(source()); @@ -88,35 +144,91 @@ void test_ParseFromArray() { sink(*buf); // $ ir } -// Serialization returning the bytes: the message taints the returned string, observed by -// parsing it into a second message and serializing that back out. +// Serialization returning the bytes: the message taints the returned string, observed by parsing it +// into a second message and serializing that back out. void test_SerializeAsString() { Person msg; std::string data = std::string(source()); - msg.ParseFromString(data); + msg.ParseFromArray(data.data(), data.size()); + std::string s = msg.SerializeAsString(); Person msg2; - msg2.ParseFromString(msg.SerializeAsString()); + msg2.ParseFromArray(s.data(), s.size()); char buf[64]; msg2.SerializeToArray(buf, sizeof(buf)); sink(*buf); // $ ir } -// Additional modeled methods, exercised so their summary steps are covered by `steps.ql`. +// Every modeled method is called below so its summary step is covered by `steps.ql`. Endpoint +// mistakes and rows that fail to bind show up as missing lines in `steps.expected`. void test_step_coverage() { Person msg; std::string data = std::string(source()); + absl::string_view sv = data; + absl::Cord cord; + + msg.ParseFromString(sv); + msg.ParseFromString(cord); + msg.ParsePartialFromString(sv); + msg.ParsePartialFromString(cord); + msg.MergeFromString(sv); + msg.MergeFromString(cord); + msg.MergePartialFromString(sv); + msg.MergePartialFromString(cord); + + msg.ParsePartialFromArray(data.data(), data.size()); - msg.MergeFromString(data); - msg.ParsePartialFromString(data); + msg.ParseFromCord(cord); + msg.ParsePartialFromCord(cord); + msg.MergeFromCord(cord); + msg.MergePartialFromCord(cord); std::istream in; msg.ParseFromIstream(&in); + msg.ParsePartialFromIstream(&in); + + google::protobuf::io::ZeroCopyInputStream zin; + msg.ParseFromZeroCopyStream(&zin); + msg.ParsePartialFromZeroCopyStream(&zin); + msg.ParseFromBoundedZeroCopyStream(&zin, 1); + msg.ParsePartialFromBoundedZeroCopyStream(&zin, 1); + msg.MergeFromBoundedZeroCopyStream(&zin, 1); + msg.MergePartialFromBoundedZeroCopyStream(&zin, 1); + + google::protobuf::io::CodedInputStream cin; + msg.ParseFromCodedStream(&cin); + msg.ParsePartialFromCodedStream(&cin); + msg.MergeFromCodedStream(&cin); + msg.MergePartialFromCodedStream(&cin); std::string out; msg.SerializeToString(&out); msg.SerializePartialToString(&out); msg.AppendToString(&out); + msg.AppendPartialToString(&out); + + char buf[64]; + msg.SerializePartialToArray(buf, sizeof(buf)); + + absl::Cord cordout; + msg.SerializeToCord(&cordout); + msg.SerializePartialToCord(&cordout); + msg.AppendToCord(&cordout); + msg.AppendPartialToCord(&cordout); std::ostream os; msg.SerializeToOstream(&os); + msg.SerializePartialToOstream(&os); + + google::protobuf::io::ZeroCopyOutputStream zout; + msg.SerializeToZeroCopyStream(&zout); + msg.SerializePartialToZeroCopyStream(&zout); + + google::protobuf::io::CodedOutputStream cout; + msg.SerializeToCodedStream(&cout); + msg.SerializePartialToCodedStream(&cout); + + msg.SerializeAsString(); + msg.SerializePartialAsString(); + msg.SerializeAsCord(); + msg.SerializePartialAsCord(); } diff --git a/cpp/ql/test/library-tests/dataflow/external-models/steps.expected b/cpp/ql/test/library-tests/dataflow/external-models/steps.expected index a1cfc6e1c3d9..833c526bce9c 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/steps.expected +++ b/cpp/ql/test/library-tests/dataflow/external-models/steps.expected @@ -4,21 +4,56 @@ | azure.cpp:262:5:262:8 | *resp | azure.cpp:262:23:262:28 | ReadToCount output argument | | azure.cpp:287:79:287:98 | call to string | azure.cpp:287:62:287:99 | call to Url | | azure.cpp:289:24:289:56 | call to GetHeader | azure.cpp:289:63:289:65 | call to Value | -| protobuf.cpp:76:22:76:25 | *data | protobuf.cpp:76:2:76:4 | ParseFromString output argument | -| protobuf.cpp:78:2:78:4 | *msg | protobuf.cpp:78:23:78:25 | SerializeToArray output argument | -| protobuf.cpp:85:21:85:31 | *call to data | protobuf.cpp:85:2:85:4 | ParseFromArray output argument | -| protobuf.cpp:87:2:87:4 | *msg | protobuf.cpp:87:23:87:25 | SerializeToArray output argument | -| protobuf.cpp:96:22:96:25 | *data | protobuf.cpp:96:2:96:4 | ParseFromString output argument | -| protobuf.cpp:98:23:98:25 | *msg | protobuf.cpp:98:27:98:43 | call to SerializeAsString | -| protobuf.cpp:98:23:98:45 | call to SerializeAsString | protobuf.cpp:98:2:98:5 | ParseFromString output argument | -| protobuf.cpp:100:2:100:5 | *msg2 | protobuf.cpp:100:24:100:26 | SerializeToArray output argument | -| protobuf.cpp:109:22:109:25 | *data | protobuf.cpp:109:2:109:4 | MergeFromString output argument | -| protobuf.cpp:110:29:110:32 | *data | protobuf.cpp:110:2:110:4 | ParsePartialFromString output argument | -| protobuf.cpp:113:23:113:25 | *& ... | protobuf.cpp:113:2:113:4 | ParseFromIstream output argument | -| protobuf.cpp:116:2:116:4 | *msg | protobuf.cpp:116:24:116:27 | SerializeToString output argument | -| protobuf.cpp:117:2:117:4 | *msg | protobuf.cpp:117:31:117:34 | SerializePartialToString output argument | -| protobuf.cpp:118:2:118:4 | *msg | protobuf.cpp:118:21:118:24 | AppendToString output argument | -| protobuf.cpp:121:2:121:4 | *msg | protobuf.cpp:121:25:121:27 | SerializeToOstream output argument | +| protobuf.cpp:141:21:141:31 | *call to data | protobuf.cpp:141:2:141:4 | ParseFromArray output argument | +| protobuf.cpp:143:2:143:4 | *msg | protobuf.cpp:143:23:143:25 | SerializeToArray output argument | +| protobuf.cpp:152:21:152:31 | *call to data | protobuf.cpp:152:2:152:4 | ParseFromArray output argument | +| protobuf.cpp:153:18:153:20 | *msg | protobuf.cpp:153:22:153:38 | call to SerializeAsString | +| protobuf.cpp:155:22:155:29 | *call to data | protobuf.cpp:155:2:155:5 | ParseFromArray output argument | +| protobuf.cpp:157:2:157:5 | *msg2 | protobuf.cpp:157:24:157:26 | SerializeToArray output argument | +| protobuf.cpp:169:22:169:23 | sv | protobuf.cpp:169:2:169:4 | ParseFromString output argument | +| protobuf.cpp:170:22:170:25 | *cord | protobuf.cpp:170:2:170:4 | ParseFromString output argument | +| protobuf.cpp:171:29:171:30 | sv | protobuf.cpp:171:2:171:4 | ParsePartialFromString output argument | +| protobuf.cpp:172:29:172:32 | *cord | protobuf.cpp:172:2:172:4 | ParsePartialFromString output argument | +| protobuf.cpp:173:22:173:23 | sv | protobuf.cpp:173:2:173:4 | MergeFromString output argument | +| protobuf.cpp:174:22:174:25 | *cord | protobuf.cpp:174:2:174:4 | MergeFromString output argument | +| protobuf.cpp:175:29:175:30 | sv | protobuf.cpp:175:2:175:4 | MergePartialFromString output argument | +| protobuf.cpp:176:29:176:32 | *cord | protobuf.cpp:176:2:176:4 | MergePartialFromString output argument | +| protobuf.cpp:178:28:178:38 | *call to data | protobuf.cpp:178:2:178:4 | ParsePartialFromArray output argument | +| protobuf.cpp:180:20:180:23 | *cord | protobuf.cpp:180:2:180:4 | ParseFromCord output argument | +| protobuf.cpp:181:27:181:30 | *cord | protobuf.cpp:181:2:181:4 | ParsePartialFromCord output argument | +| protobuf.cpp:182:20:182:23 | *cord | protobuf.cpp:182:2:182:4 | MergeFromCord output argument | +| protobuf.cpp:183:27:183:30 | *cord | protobuf.cpp:183:2:183:4 | MergePartialFromCord output argument | +| protobuf.cpp:186:23:186:25 | *& ... | protobuf.cpp:186:2:186:4 | ParseFromIstream output argument | +| protobuf.cpp:187:30:187:32 | *& ... | protobuf.cpp:187:2:187:4 | ParsePartialFromIstream output argument | +| protobuf.cpp:190:30:190:33 | *& ... | protobuf.cpp:190:2:190:4 | ParseFromZeroCopyStream output argument | +| protobuf.cpp:191:37:191:40 | *& ... | protobuf.cpp:191:2:191:4 | ParsePartialFromZeroCopyStream output argument | +| protobuf.cpp:192:37:192:40 | *& ... | protobuf.cpp:192:2:192:4 | ParseFromBoundedZeroCopyStream output argument | +| protobuf.cpp:193:44:193:47 | *& ... | protobuf.cpp:193:2:193:4 | ParsePartialFromBoundedZeroCopyStream output argument | +| protobuf.cpp:194:37:194:40 | *& ... | protobuf.cpp:194:2:194:4 | MergeFromBoundedZeroCopyStream output argument | +| protobuf.cpp:195:44:195:47 | *& ... | protobuf.cpp:195:2:195:4 | MergePartialFromBoundedZeroCopyStream output argument | +| protobuf.cpp:198:27:198:30 | *& ... | protobuf.cpp:198:2:198:4 | ParseFromCodedStream output argument | +| protobuf.cpp:199:34:199:37 | *& ... | protobuf.cpp:199:2:199:4 | ParsePartialFromCodedStream output argument | +| protobuf.cpp:200:27:200:30 | *& ... | protobuf.cpp:200:2:200:4 | MergeFromCodedStream output argument | +| protobuf.cpp:201:34:201:37 | *& ... | protobuf.cpp:201:2:201:4 | MergePartialFromCodedStream output argument | +| protobuf.cpp:204:2:204:4 | *msg | protobuf.cpp:204:24:204:27 | SerializeToString output argument | +| protobuf.cpp:205:2:205:4 | *msg | protobuf.cpp:205:31:205:34 | SerializePartialToString output argument | +| protobuf.cpp:206:2:206:4 | *msg | protobuf.cpp:206:21:206:24 | AppendToString output argument | +| protobuf.cpp:207:2:207:4 | *msg | protobuf.cpp:207:28:207:31 | AppendPartialToString output argument | +| protobuf.cpp:210:2:210:4 | *msg | protobuf.cpp:210:30:210:32 | SerializePartialToArray output argument | +| protobuf.cpp:213:2:213:4 | *msg | protobuf.cpp:213:22:213:29 | SerializeToCord output argument | +| protobuf.cpp:214:2:214:4 | *msg | protobuf.cpp:214:29:214:36 | SerializePartialToCord output argument | +| protobuf.cpp:215:2:215:4 | *msg | protobuf.cpp:215:19:215:26 | AppendToCord output argument | +| protobuf.cpp:216:2:216:4 | *msg | protobuf.cpp:216:26:216:33 | AppendPartialToCord output argument | +| protobuf.cpp:219:2:219:4 | *msg | protobuf.cpp:219:25:219:27 | SerializeToOstream output argument | +| protobuf.cpp:220:2:220:4 | *msg | protobuf.cpp:220:32:220:34 | SerializePartialToOstream output argument | +| protobuf.cpp:223:2:223:4 | *msg | protobuf.cpp:223:32:223:36 | SerializeToZeroCopyStream output argument | +| protobuf.cpp:224:2:224:4 | *msg | protobuf.cpp:224:39:224:43 | SerializePartialToZeroCopyStream output argument | +| protobuf.cpp:227:2:227:4 | *msg | protobuf.cpp:227:29:227:33 | SerializeToCodedStream output argument | +| protobuf.cpp:228:2:228:4 | *msg | protobuf.cpp:228:36:228:40 | SerializePartialToCodedStream output argument | +| protobuf.cpp:230:2:230:4 | *msg | protobuf.cpp:230:6:230:22 | call to SerializeAsString | +| protobuf.cpp:231:2:231:4 | *msg | protobuf.cpp:231:6:231:29 | call to SerializePartialAsString | +| protobuf.cpp:232:2:232:4 | *msg | protobuf.cpp:232:6:232:20 | call to SerializeAsCord | +| protobuf.cpp:233:2:233:4 | *msg | protobuf.cpp:233:6:233:27 | call to SerializePartialAsCord | | test.cpp:17:24:17:24 | x | test.cpp:17:10:17:22 | call to ymlStepManual | | test.cpp:21:27:21:27 | x | test.cpp:21:10:21:25 | call to ymlStepGenerated | | test.cpp:25:35:25:35 | x | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | 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 15ae50bddc26..b2f2e364a6b7 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/validatemodels.expected +++ b/cpp/ql/test/library-tests/dataflow/external-models/validatemodels.expected @@ -3164,6 +3164,7 @@ | Dubious signature "(const CURLU *,CURLUPart,char **,unsigned int)" in summary model. | | Dubious signature "(const ComPtr &)" in summary model. | | Dubious signature "(const Command *,const size_t,const BlockSplit *,const BlockSplit *,const BlockSplit *,const uint8_t *,size_t,size_t,uint8_t,uint8_t,const ContextType *,HistogramLiteral *,HistogramCommand *,HistogramDistance *)" in summary model. | +| Dubious signature "(const Cord &)" in summary model. | | Dubious signature "(const Curl_easy *,const connectdata *,int)" in summary model. | | Dubious signature "(const DH *)" in summary model. | | Dubious signature "(const DH *,const BIGNUM *)" in summary model. |