Skip to content

Commit 0217d11

Browse files
committed
[mlir] Fix leak in case of failed parse
A Block is optionally allocated & leaks in case of failed parse. Inline the function and ensure Block gets freed unless parse is successful. Differential Revision: https://reviews.llvm.org/D122112
1 parent 2b3becb commit 0217d11

File tree

2 files changed

+41
-34
lines changed

2 files changed

+41
-34
lines changed

mlir/lib/Parser/Parser.cpp

Lines changed: 34 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -394,10 +394,6 @@ class OperationParser : public Parser {
394394
/// us to diagnose references to blocks that are not defined precisely.
395395
Block *getBlockNamed(StringRef name, SMLoc loc);
396396

397-
/// Define the block with the specified name. Returns the Block* or nullptr in
398-
/// the case of redefinition.
399-
Block *defineBlockNamed(StringRef name, SMLoc loc, Block *existing);
400-
401397
private:
402398
/// This class represents a definition of a Block.
403399
struct BlockDefinition {
@@ -1953,11 +1949,38 @@ ParseResult OperationParser::parseBlock(Block *&block) {
19531949
if (parseToken(Token::caret_identifier, "expected block name"))
19541950
return failure();
19551951

1956-
block = defineBlockNamed(name, nameLoc, block);
1952+
// Define the block with the specified name.
1953+
auto &blockAndLoc = getBlockInfoByName(name);
1954+
blockAndLoc.loc = nameLoc;
1955+
1956+
// Use a unique pointer for in-flight block being parsed. Release ownership
1957+
// only in the case of a successful parse. This ensures that the Block
1958+
// allocated is released if the parse fails and control returns early.
1959+
std::unique_ptr<Block> inflightBlock;
1960+
1961+
// If a block has yet to be set, this is a new definition. If the caller
1962+
// provided a block, use it. Otherwise create a new one.
1963+
if (!blockAndLoc.block) {
1964+
if (block) {
1965+
blockAndLoc.block = block;
1966+
} else {
1967+
inflightBlock = std::make_unique<Block>();
1968+
blockAndLoc.block = inflightBlock.get();
1969+
}
19571970

1958-
// Fail if the block was already defined.
1959-
if (!block)
1971+
// Otherwise, the block has a forward declaration. Forward declarations are
1972+
// removed once defined, so if we are defining a existing block and it is
1973+
// not a forward declaration, then it is a redeclaration. Fail if the block
1974+
// was already defined.
1975+
} else if (!eraseForwardRef(blockAndLoc.block)) {
19601976
return emitError(nameLoc, "redefinition of block '") << name << "'";
1977+
}
1978+
1979+
// Populate the high level assembly state if necessary.
1980+
if (state.asmState)
1981+
state.asmState->addDefinition(blockAndLoc.block, nameLoc);
1982+
1983+
block = blockAndLoc.block;
19611984

19621985
// If an argument list is present, parse it.
19631986
if (getToken().is(Token::l_paren))
@@ -1967,7 +1990,10 @@ ParseResult OperationParser::parseBlock(Block *&block) {
19671990
if (parseToken(Token::colon, "expected ':' after block name"))
19681991
return failure();
19691992

1970-
return parseBlockBody(block);
1993+
ParseResult res = parseBlockBody(block);
1994+
if (succeeded(res))
1995+
inflightBlock.release();
1996+
return res;
19711997
}
19721998

19731999
ParseResult OperationParser::parseBlockBody(Block *block) {
@@ -1999,32 +2025,6 @@ Block *OperationParser::getBlockNamed(StringRef name, SMLoc loc) {
19992025
return blockDef.block;
20002026
}
20012027

2002-
/// Define the block with the specified name. Returns the Block* or nullptr in
2003-
/// the case of redefinition.
2004-
Block *OperationParser::defineBlockNamed(StringRef name, SMLoc loc,
2005-
Block *existing) {
2006-
auto &blockAndLoc = getBlockInfoByName(name);
2007-
blockAndLoc.loc = loc;
2008-
2009-
// If a block has yet to be set, this is a new definition. If the caller
2010-
// provided a block, use it. Otherwise create a new one.
2011-
if (!blockAndLoc.block) {
2012-
blockAndLoc.block = existing ? existing : new Block();
2013-
2014-
// Otherwise, the block has a forward declaration. Forward declarations are
2015-
// removed once defined, so if we are defining a existing block and it is
2016-
// not a forward declaration, then it is a redeclaration.
2017-
} else if (!eraseForwardRef(blockAndLoc.block)) {
2018-
return nullptr;
2019-
}
2020-
2021-
// Populate the high level assembly state if necessary.
2022-
if (state.asmState)
2023-
state.asmState->addDefinition(blockAndLoc.block, loc);
2024-
2025-
return blockAndLoc.block;
2026-
}
2027-
20282028
/// Parse a (possibly empty) list of SSA operands with types as block arguments
20292029
/// enclosed in parentheses.
20302030
///

mlir/test/IR/invalid-ops.mlir

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,3 +111,10 @@ func @invalid_splat(%v : f32) { // expected-note {{prior use here}}
111111
// expected-error@-1 {{expects different type than prior uses}}
112112
return
113113
}
114+
115+
// -----
116+
117+
// Case that resulted in leak previously.
118+
119+
// expected-error@+1 {{expected ':' after block name}}
120+
"g"()({^a:^b })

0 commit comments

Comments
 (0)