Skip to content

Commit 3caa09f

Browse files
authored
Add memory limit to prevent converter to AST get OOM (#8351)
1 parent 3a914af commit 3caa09f

File tree

7 files changed

+60
-4
lines changed

7 files changed

+60
-4
lines changed

ydb/library/yql/ast/yql_expr.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2709,7 +2709,7 @@ TAstParseResult ConvertToAst(const TExprNode& root, TExprContext& exprContext, c
27092709
ctx.RefAtoms = settings.RefAtoms;
27102710
ctx.AllowFreeArgs = settings.AllowFreeArgs;
27112711
ctx.NormalizeAtomFlags = settings.NormalizeAtomFlags;
2712-
ctx.Pool = std::make_unique<TMemoryPool>(4096);
2712+
ctx.Pool = std::make_unique<TMemoryPool>(4096, TMemoryPool::TExpGrow::Instance(), settings.Allocator);
27132713
ctx.Frames.push_back(TFrameContext());
27142714
ctx.CurrentFrame = &ctx.Frames.front();
27152715
VisitNode(root, 0ULL, ctx);

ydb/library/yql/ast/yql_expr.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2846,6 +2846,7 @@ struct TConvertToAstSettings {
28462846
bool PrintArguments = false;
28472847
bool AllowFreeArgs = false;
28482848
bool NormalizeAtomFlags = false;
2849+
IAllocator* Allocator = TDefaultAllocator::Instance();
28492850
};
28502851
28512852
TAstParseResult ConvertToAst(const TExprNode& root, TExprContext& ctx, const TConvertToAstSettings& settings);

ydb/library/yql/core/facade/yql_facade.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <ydb/library/yql/core/services/yql_eval_params.h>
1313
#include <ydb/library/yql/utils/log/context.h>
1414
#include <ydb/library/yql/utils/log/profile.h>
15+
#include <ydb/library/yql/utils/limiting_allocator.h>
1516
#include <ydb/library/yql/core/services/yql_out_transformers.h>
1617
#include <ydb/library/yql/core/extract_predicate/extract_predicate_dbg.h>
1718
#include <ydb/library/yql/providers/common/provider/yql_provider_names.h>
@@ -1388,7 +1389,7 @@ TFuture<IGraphTransformer::TStatus> TProgram::AsyncTransformWithFallback(bool ap
13881389
});
13891390
}
13901391

1391-
TMaybe<TString> TProgram::GetQueryAst() {
1392+
TMaybe<TString> TProgram::GetQueryAst(TMaybe<size_t> memoryLimit) {
13921393
if (ExternalQueryAst_) {
13931394
return ExternalQueryAst_;
13941395
}
@@ -1397,7 +1398,17 @@ TMaybe<TString> TProgram::GetQueryAst() {
13971398
astStream.Reserve(DEFAULT_AST_BUF_SIZE);
13981399

13991400
if (ExprRoot_) {
1400-
auto ast = ConvertToAst(*ExprRoot_, *ExprCtx_, TExprAnnotationFlags::None, true);
1401+
std::unique_ptr<IAllocator> limitingAllocator;
1402+
TConvertToAstSettings settings;
1403+
settings.AnnotationFlags = TExprAnnotationFlags::None;
1404+
settings.RefAtoms = true;
1405+
settings.Allocator = TDefaultAllocator::Instance();
1406+
if (memoryLimit) {
1407+
limitingAllocator = MakeLimitingAllocator(*memoryLimit, TDefaultAllocator::Instance());
1408+
settings.Allocator = limitingAllocator.get();
1409+
}
1410+
1411+
auto ast = ConvertToAst(*ExprRoot_, *ExprCtx_, settings);
14011412
ast.Root->PrettyPrintTo(astStream, TAstPrintFlags::ShortQuote | TAstPrintFlags::PerLine);
14021413
return astStream.Str();
14031414
} else if (AstRoot_) {

ydb/library/yql/core/facade/yql_facade.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ class TProgram: public TThrRefBase, private TNonCopyable
223223
return ResultProviderConfig_->CommittedResults;
224224
}
225225

226-
TMaybe<TString> GetQueryAst();
226+
TMaybe<TString> GetQueryAst(TMaybe<size_t> memoryLimit = {});
227227
TMaybe<TString> GetQueryPlan(const TPlanSettings& settings = {});
228228

229229
void SetDiagnosticFormat(NYson::EYsonFormat format) {
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#include "limiting_allocator.h"
2+
3+
#include <util/memory/pool.h>
4+
#include <util/generic/yexception.h>
5+
6+
namespace {
7+
class TLimitingAllocator : public IAllocator {
8+
public:
9+
TLimitingAllocator(size_t limit, IAllocator* allocator) : Alloc_(allocator), Limit_(limit) {};
10+
TBlock Allocate(size_t len) override final {
11+
if (Allocated_ + len > Limit_) {
12+
throw std::runtime_error("Out of memory");
13+
}
14+
Allocated_ += len;
15+
return Alloc_->Allocate(len);
16+
}
17+
18+
void Release(const TBlock& block) override final {
19+
Y_ENSURE(Allocated_ >= block.Len);
20+
Allocated_ -= block.Len;
21+
Alloc_->Release(block);
22+
}
23+
24+
private:
25+
IAllocator* Alloc_;
26+
size_t Allocated_ = 0;
27+
const size_t Limit_;
28+
};
29+
}
30+
31+
namespace NYql {
32+
std::unique_ptr<IAllocator> MakeLimitingAllocator(size_t limit, IAllocator* underlying) {
33+
return std::make_unique<TLimitingAllocator>(limit, underlying);
34+
}
35+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#pragma once
2+
3+
#include <util/memory/pool.h>
4+
#include <memory>
5+
6+
namespace NYql {
7+
std::unique_ptr<IAllocator> MakeLimitingAllocator(size_t limit, IAllocator* underlying);
8+
}

ydb/library/yql/utils/ya.make

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ SRCS(
1010
future_action.h
1111
hash.cpp
1212
hash.h
13+
limiting_allocator.cpp
1314
md5_stream.cpp
1415
md5_stream.h
1516
method_index.cpp

0 commit comments

Comments
 (0)