From 57c92ea83a479fb997550e25eb10c8d206ec1129 Mon Sep 17 00:00:00 2001 From: AkshayK Date: Mon, 14 Sep 2026 18:26:46 -0400 Subject: [PATCH 1/2] C++: Model BDE Base64 and hex pointer-buffer conversions --- .../2026-09-14-bdlde-conversion-models.md | 4 + cpp/ql/lib/ext/bdlde.model.yml | 18 +++ .../test/library-tests/dataflow/bdlde/bdlde.h | 38 +++++ .../dataflow/bdlde/flow.expected | 0 .../test/library-tests/dataflow/bdlde/flow.ql | 19 +++ .../library-tests/dataflow/bdlde/test.cpp | 153 ++++++++++++++++++ .../external-models/validatemodels.expected | 1 + 7 files changed, 233 insertions(+) create mode 100644 cpp/ql/lib/change-notes/2026-09-14-bdlde-conversion-models.md create mode 100644 cpp/ql/lib/ext/bdlde.model.yml create mode 100644 cpp/ql/test/library-tests/dataflow/bdlde/bdlde.h create mode 100644 cpp/ql/test/library-tests/dataflow/bdlde/flow.expected create mode 100644 cpp/ql/test/library-tests/dataflow/bdlde/flow.ql create mode 100644 cpp/ql/test/library-tests/dataflow/bdlde/test.cpp diff --git a/cpp/ql/lib/change-notes/2026-09-14-bdlde-conversion-models.md b/cpp/ql/lib/change-notes/2026-09-14-bdlde-conversion-models.md new file mode 100644 index 000000000000..fbab5911ac5a --- /dev/null +++ b/cpp/ql/lib/change-notes/2026-09-14-bdlde-conversion-models.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Added taint-flow models for direct pointer-buffer conversions using `BloombergLP::bdlde::Base64Encoder`, `Base64Decoder`, `HexEncoder`, and `HexDecoder`. diff --git a/cpp/ql/lib/ext/bdlde.model.yml b/cpp/ql/lib/ext/bdlde.model.yml new file mode 100644 index 000000000000..4e88f7927799 --- /dev/null +++ b/cpp/ql/lib/ext/bdlde.model.yml @@ -0,0 +1,18 @@ +# Direct pointer-buffer conversion models for the public BDE bdlde API. +# https://github.com/bloomberg/bde/tree/ec310b87e008199ecbdbc00a0b0264a53d806a0a/groups/bdl/bdlde +# These summaries do not model retained data across calls or class-based iterators. +extensions: + - addsTo: + pack: codeql/cpp-all + extensible: summaryModel + data: # namespace, type, subtypes, name, signature, ext, input, output, kind, provenance + # Only begin supplies input bytes. end is exclusive; numOut/numIn are outputs. + # The longer overload has six parameters, including the defaulted maxNumOut. + - ["BloombergLP::bdlde", "Base64Encoder", False, "convert", "(OUT,IN,IN)", "", "Argument[*1]", "Argument[*0]", "taint", "manual"] + - ["BloombergLP::bdlde", "Base64Encoder", False, "convert", "(OUT,int *,int *,IN,IN,int)", "", "Argument[*3]", "Argument[*0]", "taint", "manual"] + - ["BloombergLP::bdlde", "Base64Decoder", False, "convert", "(OUT,IN,IN)", "", "Argument[*1]", "Argument[*0]", "taint", "manual"] + - ["BloombergLP::bdlde", "Base64Decoder", False, "convert", "(OUT,int *,int *,IN,IN,int)", "", "Argument[*3]", "Argument[*0]", "taint", "manual"] + - ["BloombergLP::bdlde", "HexEncoder", False, "convert", "(OUT,IN,IN)", "", "Argument[*1]", "Argument[*0]", "taint", "manual"] + - ["BloombergLP::bdlde", "HexEncoder", False, "convert", "(OUT,int *,int *,IN,IN,int)", "", "Argument[*3]", "Argument[*0]", "taint", "manual"] + - ["BloombergLP::bdlde", "HexDecoder", False, "convert", "(OUT,IN,IN)", "", "Argument[*1]", "Argument[*0]", "taint", "manual"] + - ["BloombergLP::bdlde", "HexDecoder", False, "convert", "(OUT,int *,int *,IN,IN,int)", "", "Argument[*3]", "Argument[*0]", "taint", "manual"] diff --git a/cpp/ql/test/library-tests/dataflow/bdlde/bdlde.h b/cpp/ql/test/library-tests/dataflow/bdlde/bdlde.h new file mode 100644 index 000000000000..9858c274ec19 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/bdlde/bdlde.h @@ -0,0 +1,38 @@ +// Minimal public declarations, with implementation bodies omitted to test the models. +// https://github.com/bloomberg/bde/tree/ec310b87e008199ecbdbc00a0b0264a53d806a0a/groups/bdl/bdlde +namespace BloombergLP { +namespace bdlde { +class Base64Encoder { +public: + template + int convert(OUTPUT_ITERATOR out, INPUT_ITERATOR begin, INPUT_ITERATOR end); + template + int convert(OUTPUT_ITERATOR out, int *numOut, int *numIn, + INPUT_ITERATOR begin, INPUT_ITERATOR end, int maxNumOut = -1); +}; +class Base64Decoder { +public: + template + int convert(OUTPUT_ITERATOR out, INPUT_ITERATOR begin, INPUT_ITERATOR end); + template + int convert(OUTPUT_ITERATOR out, int *numOut, int *numIn, + INPUT_ITERATOR begin, INPUT_ITERATOR end, int maxNumOut = -1); +}; +class HexEncoder { +public: + template + int convert(OUTPUT_ITERATOR out, INPUT_ITERATOR begin, INPUT_ITERATOR end); + template + int convert(OUTPUT_ITERATOR out, int *numOut, int *numIn, + INPUT_ITERATOR begin, INPUT_ITERATOR end, int maxNumOut = -1); +}; +class HexDecoder { +public: + template + int convert(OUTPUT_ITERATOR out, INPUT_ITERATOR begin, INPUT_ITERATOR end); + template + int convert(OUTPUT_ITERATOR out, int *numOut, int *numIn, + INPUT_ITERATOR begin, INPUT_ITERATOR end, int maxNumOut = -1); +}; +} +} diff --git a/cpp/ql/test/library-tests/dataflow/bdlde/flow.expected b/cpp/ql/test/library-tests/dataflow/bdlde/flow.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/cpp/ql/test/library-tests/dataflow/bdlde/flow.ql b/cpp/ql/test/library-tests/dataflow/bdlde/flow.ql new file mode 100644 index 000000000000..6bdf085e721b --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/bdlde/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/bdlde/test.cpp b/cpp/ql/test/library-tests/dataflow/bdlde/test.cpp new file mode 100644 index 000000000000..0766fe1915de --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/bdlde/test.cpp @@ -0,0 +1,153 @@ +#include "bdlde.h" + +char source(); +void sink(char); + +void testBase64Encoder() { + BloombergLP::bdlde::Base64Encoder converter; + char input[] = {source(), 'A', 'A', 'A'}; + const char *begin = input; + char shortOutput[32] = {}; + converter.convert(shortOutput, input, input + 4); + sink(shortOutput[0]); // $ ir + + int numOut = 0, numIn = 0; + char defaultLimitOutput[32] = {}; + converter.convert(defaultLimitOutput, &numOut, &numIn, begin, begin + 4); + sink(defaultLimitOutput[0]); // $ ir + + char explicitLimitOutput[32] = {}; + converter.convert(explicitLimitOutput, &numOut, &numIn, begin, begin + 4, 32); + sink(explicitLimitOutput[0]); // $ ir +} + +void testBase64EncoderNonInputs() { + BloombergLP::bdlde::Base64Encoder converter; + const char input[] = "AAAA"; + int numOut = source(), numIn = source(); + char output[32] = {}; + converter.convert(output, &numOut, &numIn, input, input + 4); + sink(output[0]); // No flow from the pre-call values of the output counters. + + char limitedOutput[32] = {}; + converter.convert(limitedOutput, &numOut, &numIn, input, input + 4, source()); + sink(limitedOutput[0]); // The output limit does not supply output bytes. +} + +void testBase64Decoder() { + BloombergLP::bdlde::Base64Decoder converter; + char input[] = {source(), 'A', 'A', 'A'}; + const char *begin = input; + char shortOutput[32] = {}; + converter.convert(shortOutput, input, input + 4); + sink(shortOutput[0]); // $ ir + + int numOut = 0, numIn = 0; + char defaultLimitOutput[32] = {}; + converter.convert(defaultLimitOutput, &numOut, &numIn, begin, begin + 4); + sink(defaultLimitOutput[0]); // $ ir + + char explicitLimitOutput[32] = {}; + converter.convert(explicitLimitOutput, &numOut, &numIn, begin, begin + 4, 32); + sink(explicitLimitOutput[0]); // $ ir +} + +void testBase64DecoderNonInputs() { + BloombergLP::bdlde::Base64Decoder converter; + const char input[] = "AAAA"; + int numOut = source(), numIn = source(); + char output[32] = {}; + converter.convert(output, &numOut, &numIn, input, input + 4); + sink(output[0]); // No flow from the pre-call values of the output counters. + + char limitedOutput[32] = {}; + converter.convert(limitedOutput, &numOut, &numIn, input, input + 4, source()); + sink(limitedOutput[0]); // The output limit does not supply output bytes. +} + +void testHexEncoder() { + BloombergLP::bdlde::HexEncoder converter; + char input[] = {source(), 'A', 'A', 'A'}; + const char *begin = input; + char shortOutput[32] = {}; + converter.convert(shortOutput, input, input + 4); + sink(shortOutput[0]); // $ ir + + int numOut = 0, numIn = 0; + char defaultLimitOutput[32] = {}; + converter.convert(defaultLimitOutput, &numOut, &numIn, begin, begin + 4); + sink(defaultLimitOutput[0]); // $ ir + + char explicitLimitOutput[32] = {}; + converter.convert(explicitLimitOutput, &numOut, &numIn, begin, begin + 4, 32); + sink(explicitLimitOutput[0]); // $ ir +} + +void testHexEncoderNonInputs() { + BloombergLP::bdlde::HexEncoder converter; + const char input[] = "AAAA"; + int numOut = source(), numIn = source(); + char output[32] = {}; + converter.convert(output, &numOut, &numIn, input, input + 4); + sink(output[0]); // No flow from the pre-call values of the output counters. + + char limitedOutput[32] = {}; + converter.convert(limitedOutput, &numOut, &numIn, input, input + 4, source()); + sink(limitedOutput[0]); // The output limit does not supply output bytes. +} + +void testHexDecoder() { + BloombergLP::bdlde::HexDecoder converter; + char input[] = {source(), 'A', 'A', 'A'}; + const char *begin = input; + char shortOutput[32] = {}; + converter.convert(shortOutput, input, input + 4); + sink(shortOutput[0]); // $ ir + + int numOut = 0, numIn = 0; + char defaultLimitOutput[32] = {}; + converter.convert(defaultLimitOutput, &numOut, &numIn, begin, begin + 4); + sink(defaultLimitOutput[0]); // $ ir + + char explicitLimitOutput[32] = {}; + converter.convert(explicitLimitOutput, &numOut, &numIn, begin, begin + 4, 32); + sink(explicitLimitOutput[0]); // $ ir +} + +void testHexDecoderNonInputs() { + BloombergLP::bdlde::HexDecoder converter; + const char input[] = "AAAA"; + int numOut = source(), numIn = source(); + char output[32] = {}; + converter.convert(output, &numOut, &numIn, input, input + 4); + sink(output[0]); // No flow from the pre-call values of the output counters. + + char limitedOutput[32] = {}; + converter.convert(limitedOutput, &numOut, &numIn, input, input + 4, source()); + sink(limitedOutput[0]); // The output limit does not supply output bytes. +} + +// Inherited calls still target the method declared in Base64Encoder. +struct DerivedEncoder : BloombergLP::bdlde::Base64Encoder {}; + +void testInheritedConvert() { + DerivedEncoder converter; + char input[] = {source()}; + char output[32] = {}; + converter.convert(output, input, input + 1); + sink(output[0]); // $ ir +} + +// A different method that hides convert must not inherit the summary. +struct HidingEncoder : BloombergLP::bdlde::Base64Encoder { + template + int convert(OUTPUT_ITERATOR out, INPUT_ITERATOR begin, INPUT_ITERATOR end); +}; + +void testHiddenConvert() { + HidingEncoder converter; + char input[] = {source()}; + char output[32] = {}; + converter.convert(output, input, input + 1); + sink(output[0]); // No modeled flow for the hiding method. +} 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..59e4b92dee39 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/validatemodels.expected +++ b/cpp/ql/test/library-tests/dataflow/external-models/validatemodels.expected @@ -1873,6 +1873,7 @@ | Dubious signature "(OTHERNAME *)" in summary model. | | Dubious signature "(OTHERNAME **,const unsigned char **,long)" in summary model. | | Dubious signature "(OTHERNAME *,OTHERNAME *)" in summary model. | +| Dubious signature "(OUT,int *,int *,IN,IN,int)" in summary model. | | Dubious signature "(OperationConfig *)" in summary model. | | Dubious signature "(OperationConfig *,HttpReq,HttpReq *)" in summary model. | | Dubious signature "(OperationConfig *,const char *,tool_mime **,tool_mime **,bool)" in summary model. | From e5189767fce74a109e7bf500ba3a3c4c6101665a Mon Sep 17 00:00:00 2001 From: AkshayK Date: Mon, 14 Sep 2026 18:47:21 -0400 Subject: [PATCH 2/2] C++: Restrict BDE conversion models to pointer instantiations --- cpp/ql/lib/ext/bdlde.model.yml | 18 --- cpp/ql/lib/semmle/code/cpp/models/Models.qll | 1 + .../code/cpp/models/implementations/Bdlde.qll | 32 +++++ .../dataflow/bdlde/iterators.cpp | 130 ++++++++++++++++++ .../external-models/validatemodels.expected | 1 - 5 files changed, 163 insertions(+), 19 deletions(-) delete mode 100644 cpp/ql/lib/ext/bdlde.model.yml create mode 100644 cpp/ql/lib/semmle/code/cpp/models/implementations/Bdlde.qll create mode 100644 cpp/ql/test/library-tests/dataflow/bdlde/iterators.cpp diff --git a/cpp/ql/lib/ext/bdlde.model.yml b/cpp/ql/lib/ext/bdlde.model.yml deleted file mode 100644 index 4e88f7927799..000000000000 --- a/cpp/ql/lib/ext/bdlde.model.yml +++ /dev/null @@ -1,18 +0,0 @@ -# Direct pointer-buffer conversion models for the public BDE bdlde API. -# https://github.com/bloomberg/bde/tree/ec310b87e008199ecbdbc00a0b0264a53d806a0a/groups/bdl/bdlde -# These summaries do not model retained data across calls or class-based iterators. -extensions: - - addsTo: - pack: codeql/cpp-all - extensible: summaryModel - data: # namespace, type, subtypes, name, signature, ext, input, output, kind, provenance - # Only begin supplies input bytes. end is exclusive; numOut/numIn are outputs. - # The longer overload has six parameters, including the defaulted maxNumOut. - - ["BloombergLP::bdlde", "Base64Encoder", False, "convert", "(OUT,IN,IN)", "", "Argument[*1]", "Argument[*0]", "taint", "manual"] - - ["BloombergLP::bdlde", "Base64Encoder", False, "convert", "(OUT,int *,int *,IN,IN,int)", "", "Argument[*3]", "Argument[*0]", "taint", "manual"] - - ["BloombergLP::bdlde", "Base64Decoder", False, "convert", "(OUT,IN,IN)", "", "Argument[*1]", "Argument[*0]", "taint", "manual"] - - ["BloombergLP::bdlde", "Base64Decoder", False, "convert", "(OUT,int *,int *,IN,IN,int)", "", "Argument[*3]", "Argument[*0]", "taint", "manual"] - - ["BloombergLP::bdlde", "HexEncoder", False, "convert", "(OUT,IN,IN)", "", "Argument[*1]", "Argument[*0]", "taint", "manual"] - - ["BloombergLP::bdlde", "HexEncoder", False, "convert", "(OUT,int *,int *,IN,IN,int)", "", "Argument[*3]", "Argument[*0]", "taint", "manual"] - - ["BloombergLP::bdlde", "HexDecoder", False, "convert", "(OUT,IN,IN)", "", "Argument[*1]", "Argument[*0]", "taint", "manual"] - - ["BloombergLP::bdlde", "HexDecoder", False, "convert", "(OUT,int *,int *,IN,IN,int)", "", "Argument[*3]", "Argument[*0]", "taint", "manual"] diff --git a/cpp/ql/lib/semmle/code/cpp/models/Models.qll b/cpp/ql/lib/semmle/code/cpp/models/Models.qll index 54dc0fa0ff64..e2e33b7d9497 100644 --- a/cpp/ql/lib/semmle/code/cpp/models/Models.qll +++ b/cpp/ql/lib/semmle/code/cpp/models/Models.qll @@ -1,4 +1,5 @@ private import implementations.Allocation +private import implementations.Bdlde private import implementations.Deallocation private import implementations.Fopen private import implementations.Fread diff --git a/cpp/ql/lib/semmle/code/cpp/models/implementations/Bdlde.qll b/cpp/ql/lib/semmle/code/cpp/models/implementations/Bdlde.qll new file mode 100644 index 000000000000..412fe4d03c9b --- /dev/null +++ b/cpp/ql/lib/semmle/code/cpp/models/implementations/Bdlde.qll @@ -0,0 +1,32 @@ +/** + * Models direct pointer-buffer conversions in the BDE bdlde library. + * See https://github.com/bloomberg/bde/tree/ec310b87e008199ecbdbc00a0b0264a53d806a0a/groups/bdl/bdlde. + */ + +import semmle.code.cpp.models.interfaces.Taint + +/** A conversion whose input and output iterators are pointers. */ +private class BdldePointerConversion extends TaintFunction { + int beginIndex; + + BdldePointerConversion() { + this.hasName("convert") and + this.getDeclaringType() + .hasQualifiedName("BloombergLP::bdlde", + ["Base64Encoder", "Base64Decoder", "HexEncoder", "HexDecoder"]) and + ( + this.getNumberOfParameters() = 3 and beginIndex = 1 + or + this.getNumberOfParameters() = 6 and beginIndex = 3 + ) and + // Check instantiated types. A generic template signature would also match + // iterator objects and replace their bodies with an inapplicable summary. + this.getParameter(0).getUnspecifiedType() instanceof PointerType and + this.getParameter(beginIndex).getUnspecifiedType() instanceof PointerType and + this.getParameter(beginIndex + 1).getUnspecifiedType() instanceof PointerType + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + input.isParameterDeref(beginIndex) and output.isParameterDeref(0) + } +} diff --git a/cpp/ql/test/library-tests/dataflow/bdlde/iterators.cpp b/cpp/ql/test/library-tests/dataflow/bdlde/iterators.cpp new file mode 100644 index 000000000000..3c2d6e5b64b6 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/bdlde/iterators.cpp @@ -0,0 +1,130 @@ +#include "bdlde.h" + +char source(); +void sink(char); + +// Reduced iterator access bodies: the object instantiations must remain +// analyzable rather than being replaced by pointer-buffer summaries. +struct InputIterator { + char value; + char operator*() const { return value; } +}; + +struct OutputIterator { + OutputIterator &operator*() { return *this; } + void operator=(char value) { sink(value); } // $ ir +}; + +namespace BloombergLP { +namespace bdlde { +template +int Base64Encoder::convert(OUT out, IN begin, IN end) { + *out = *begin; + return 0; +} + +template +int Base64Encoder::convert(OUT out, int *numOut, int *numIn, IN begin, IN end, int limit) { + *out = *begin; + return 0; +} +template +int Base64Decoder::convert(OUT out, IN begin, IN end) { + *out = *begin; + return 0; +} + +template +int Base64Decoder::convert(OUT out, int *numOut, int *numIn, IN begin, IN end, int limit) { + *out = *begin; + return 0; +} +template +int HexEncoder::convert(OUT out, IN begin, IN end) { + *out = *begin; + return 0; +} + +template +int HexEncoder::convert(OUT out, int *numOut, int *numIn, IN begin, IN end, int limit) { + *out = *begin; + return 0; +} +template +int HexDecoder::convert(OUT out, IN begin, IN end) { + *out = *begin; + return 0; +} + +template +int HexDecoder::convert(OUT out, int *numOut, int *numIn, IN begin, IN end, int limit) { + *out = *begin; + return 0; +} +} +} + +void iteratorBase64Encoder() { + BloombergLP::bdlde::Base64Encoder converter; + InputIterator begin = {source()}, end = {0}; + char shortOutput[4] = {}; + converter.convert(shortOutput, begin, end); + sink(shortOutput[0]); // $ ir + int numOut = 0, numIn = 0; + char longOutput[4] = {}; + converter.convert(longOutput, &numOut, &numIn, begin, end); + sink(longOutput[0]); // $ ir +} + +void iteratorBase64Decoder() { + BloombergLP::bdlde::Base64Decoder converter; + InputIterator begin = {source()}, end = {0}; + char shortOutput[4] = {}; + converter.convert(shortOutput, begin, end); + sink(shortOutput[0]); // $ ir + int numOut = 0, numIn = 0; + char longOutput[4] = {}; + converter.convert(longOutput, &numOut, &numIn, begin, end); + sink(longOutput[0]); // $ ir +} + +void iteratorHexEncoder() { + BloombergLP::bdlde::HexEncoder converter; + InputIterator begin = {source()}, end = {0}; + char shortOutput[4] = {}; + converter.convert(shortOutput, begin, end); + sink(shortOutput[0]); // $ ir + int numOut = 0, numIn = 0; + char longOutput[4] = {}; + converter.convert(longOutput, &numOut, &numIn, begin, end); + sink(longOutput[0]); // $ ir +} + +void iteratorHexDecoder() { + BloombergLP::bdlde::HexDecoder converter; + InputIterator begin = {source()}, end = {0}; + char shortOutput[4] = {}; + converter.convert(shortOutput, begin, end); + sink(shortOutput[0]); // $ ir + int numOut = 0, numIn = 0; + char longOutput[4] = {}; + converter.convert(longOutput, &numOut, &numIn, begin, end); + sink(longOutput[0]); // $ ir +} + +template +void outputIterator() { + CONVERTER converter; + char input[] = {source()}; + OutputIterator out; + converter.convert(out, input, input + 1); + int numOut = 0, numIn = 0; + converter.convert(out, &numOut, &numIn, input, input + 1); +} + +void testOutputIterators() { + outputIterator(); + outputIterator(); + outputIterator(); + outputIterator(); +} 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 59e4b92dee39..d5b0b0cc0213 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/validatemodels.expected +++ b/cpp/ql/test/library-tests/dataflow/external-models/validatemodels.expected @@ -1873,7 +1873,6 @@ | Dubious signature "(OTHERNAME *)" in summary model. | | Dubious signature "(OTHERNAME **,const unsigned char **,long)" in summary model. | | Dubious signature "(OTHERNAME *,OTHERNAME *)" in summary model. | -| Dubious signature "(OUT,int *,int *,IN,IN,int)" in summary model. | | Dubious signature "(OperationConfig *)" in summary model. | | Dubious signature "(OperationConfig *,HttpReq,HttpReq *)" in summary model. | | Dubious signature "(OperationConfig *,const char *,tool_mime **,tool_mime **,bool)" in summary model. |