[llvm] [mlir] [MLIR][ADT] Fix uninitialized scalar and array-vs-singleton patterns flagged by Coverity in generated code (PR #215217)
Sylvestre Ledru via llvm-commits
llvm-commits at lists.llvm.org
Mon Aug 10 01:47:34 PDT 2026
https://github.com/sylvestre updated https://github.com/llvm/llvm-project/pull/215217
>From c21228f7636b7991150d1b11e6f9af1eec801cc0 Mon Sep 17 00:00:00 2001
From: Sylvestre Ledru <sylvestre at debian.org>
Date: Mon, 10 Aug 2026 09:23:11 +0200
Subject: [PATCH 1/2] [ADT] Initialize function_ref::callable
A default-constructed function_ref initialized callback but left the
callable field indeterminate. The value is then copied whenever such an
empty function_ref is copied or moved (e.g. OperationState's
propertiesDeleter/propertiesSetter members in every generated MLIR
Op::create method), and operator== reads it, which is undefined
behavior for empty refs.
Coverity reports this as 'Uninitialized scalar variable' at every use
site: 7,201 outstanding findings in the LLVM Coverity project, 6,436 of
them in tblgen-generated Op::create methods. Initializing the field
fixes the entire class at the root for one store.
---
llvm/include/llvm/ADT/STLFunctionalExtras.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/include/llvm/ADT/STLFunctionalExtras.h b/llvm/include/llvm/ADT/STLFunctionalExtras.h
index a4d50dc3648be..f6dbd8b1840ac 100644
--- a/llvm/include/llvm/ADT/STLFunctionalExtras.h
+++ b/llvm/include/llvm/ADT/STLFunctionalExtras.h
@@ -39,7 +39,7 @@ template<typename Fn> class function_ref;
template <typename Ret, typename... Params>
class LLVM_GSL_POINTER function_ref<Ret(Params...)> {
Ret (*callback)(intptr_t callable, Params ...params) = nullptr;
- intptr_t callable;
+ intptr_t callable = 0;
template<typename Callable>
static Ret callback_fn(intptr_t callable, Params ...params) {
>From 924ba81927a2f92eee5c02bd7f1d492d8a99c6c5 Mon Sep 17 00:00:00 2001
From: Sylvestre Ledru <sylvestre at debian.org>
Date: Mon, 10 Aug 2026 09:30:49 +0200
Subject: [PATCH 2/2] [mlir-tblgen] Emit one-element arrays instead of
ArrayRef(&scalar, 1)
For single (non-variadic) operands and types, the generated parse
methods declared a scalar and wrapped its address in an ArrayRef:
::mlir::OpAsmParser::UnresolvedOperand argRawOperand{};
::llvm::ArrayRef<...> argOperands(&argRawOperand, 1);
Coverity's ARRAY_VS_SINGLETON checker flags every such use as
'Out-of-bounds access' -- 1,482 outstanding findings across the
generated *Ops.cpp.inc files. Emit a one-element array instead, which
expresses the same thing without pointer arithmetic on a singleton:
::mlir::OpAsmParser::UnresolvedOperand argRawOperands[1] = {};
::llvm::ArrayRef<...> argOperands(argRawOperands);
No functional change to the generated parsers.
---
mlir/tools/mlir-tblgen/OpFormatGen.cpp | 23 +++++++++++------------
1 file changed, 11 insertions(+), 12 deletions(-)
diff --git a/mlir/tools/mlir-tblgen/OpFormatGen.cpp b/mlir/tools/mlir-tblgen/OpFormatGen.cpp
index 2ae276a62e939..49acc7effc4f1 100644
--- a/mlir/tools/mlir-tblgen/OpFormatGen.cpp
+++ b/mlir/tools/mlir-tblgen/OpFormatGen.cpp
@@ -590,7 +590,7 @@ const char *const optionalOperandParserCode = R"(
)";
const char *const operandParserCode = R"(
{0}OperandsLoc = parser.getCurrentLocation();
- if (parser.parseOperand({0}RawOperand))
+ if (parser.parseOperand({0}RawOperands[0]))
return ::mlir::failure();
)";
/// The code snippet used to generate a parser call for a VariadicOfVariadic
@@ -646,11 +646,11 @@ const char *const typeParserCode = R"(
{0} type;
if (parser.parseCustomTypeWithFallback(type))
return ::mlir::failure();
- {1}RawType = type;
+ {1}RawTypes[0] = type;
}
)";
const char *const qualifiedTypeParserCode = R"(
- if (parser.parseType({1}RawType))
+ if (parser.parseType({1}RawTypes[0]))
return ::mlir::failure();
)";
@@ -924,9 +924,9 @@ static void genElementParserStorage(FormatElement *element, const Operator &op,
}
} else {
body << " ::mlir::OpAsmParser::UnresolvedOperand " << name
- << "RawOperand{};\n"
+ << "RawOperands[1] = {};\n"
<< " ::llvm::ArrayRef<::mlir::OpAsmParser::UnresolvedOperand> "
- << name << "Operands(&" << name << "RawOperand, 1);";
+ << name << "Operands(" << name << "RawOperands);";
}
body << formatv(" ::llvm::SMLoc {0}OperandsLoc;\n"
" (void){0}OperandsLoc;\n",
@@ -961,11 +961,10 @@ static void genElementParserStorage(FormatElement *element, const Operator &op,
if (lengthKind != ArgumentLengthKind::Single)
body << " ::llvm::SmallVector<::mlir::Type, 1> " << name << "Types;\n";
else
- body
- << formatv(" ::mlir::Type {0}RawType{{};\n", name)
- << formatv(
- " ::llvm::ArrayRef<::mlir::Type> {0}Types(&{0}RawType, 1);\n",
- name);
+ body << formatv(" ::mlir::Type {0}RawTypes[1] = {{};\n", name)
+ << formatv(
+ " ::llvm::ArrayRef<::mlir::Type> {0}Types({0}RawTypes);\n",
+ name);
} else if (auto *dir = dyn_cast<FunctionalTypeDirective>(element)) {
ArgumentLengthKind ignored;
body << " ::llvm::ArrayRef<::mlir::Type> "
@@ -994,7 +993,7 @@ static void genCustomParameterParser(FormatElement *param, MethodBody &body,
else if (lengthKind == ArgumentLengthKind::Optional)
body << formatv("{0}Operand", name);
else
- body << formatv("{0}RawOperand", name);
+ body << formatv("{0}RawOperands[0]", name);
} else if (auto *region = dyn_cast<RegionVariable>(param)) {
StringRef name = region->getVar()->name;
@@ -1023,7 +1022,7 @@ static void genCustomParameterParser(FormatElement *param, MethodBody &body,
else if (lengthKind == ArgumentLengthKind::Optional)
body << formatv("{0}Type", listName);
else
- body << formatv("{0}RawType", listName);
+ body << formatv("{0}RawTypes[0]", listName);
} else if (auto *string = dyn_cast<StringElement>(param)) {
FmtContext ctx;
More information about the llvm-commits
mailing list