diff options
| author | Even Rouault <even.rouault@spatialys.com> | 2019-09-06 11:29:07 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-09-06 11:29:07 +0200 |
| commit | 73ccf7e1ba2ba9e927c4eaef81f5237fb4f587b2 (patch) | |
| tree | 7e6996f97af28d1fca89a47edc8bb3bb3c42a9e9 | |
| parent | b7ed294cff05f42ef24a212c85a10106565eef35 (diff) | |
| parent | 9c38babea4650a20ec94eff9ab644f5c84c89874 (diff) | |
| download | PROJ-73ccf7e1ba2ba9e927c4eaef81f5237fb4f587b2.tar.gz PROJ-73ccf7e1ba2ba9e927c4eaef81f5237fb4f587b2.zip | |
Merge pull request #1589 from rouault/fix_1574
PROJStringParser::createFromPROJString(): avoid potential infinite recursion (fixes #1574)
| -rw-r--r-- | src/iso19111/io.cpp | 72 | ||||
| -rw-r--r-- | src/proj_internal.h | 2 |
2 files changed, 49 insertions, 25 deletions
diff --git a/src/iso19111/io.cpp b/src/iso19111/io.cpp index 4d8fe285..eccb034d 100644 --- a/src/iso19111/io.cpp +++ b/src/iso19111/io.cpp @@ -8638,6 +8638,21 @@ static const metadata::ExtentPtr &getExtent(const crs::CRS *crs) { //! @endcond +namespace { +struct PJContextHolder { + PJ_CONTEXT *ctx_; + bool bFree_; + + PJContextHolder(PJ_CONTEXT *ctx, bool bFree) : ctx_(ctx), bFree_(bFree) {} + ~PJContextHolder() { + if (bFree_) + proj_context_destroy(ctx_); + } + PJContextHolder(const PJContextHolder &) = delete; + PJContextHolder &operator=(const PJContextHolder &) = delete; +}; +} // namespace + // --------------------------------------------------------------------------- /** \brief Instantiate a sub-class of BaseObject from a PROJ string. @@ -8652,8 +8667,10 @@ PROJStringParser::createFromPROJString(const std::string &projString) { // In some abnormal situations involving init=epsg:XXXX syntax, we could // have infinite loop - if (d->ctx_ && d->ctx_->curStringInCreateFromPROJString == projString) { - throw ParsingException("invalid PROJ string"); + if (d->ctx_ && + d->ctx_->projStringParserCreateFromPROJStringRecursionCounter == 2) { + throw ParsingException( + "Infinite recursion in PROJStringParser::createFromPROJString()"); } d->steps_.clear(); @@ -8701,27 +8718,38 @@ PROJStringParser::createFromPROJString(const std::string &projString) { const std::string &stepName = d->steps_[0].name; if (ci_starts_with(stepName, "epsg:") || ci_starts_with(stepName, "IGNF:")) { + + /* We create a new context so as to avoid messing up with the */ + /* errorno of the main context, when trying to find the likely */ + /* missing epsg file */ + auto ctx = proj_context_create(); + if (!ctx) { + throw ParsingException("out of memory"); + } + PJContextHolder contextHolder(ctx, true); + if (d->ctx_) { + ctx->set_search_paths(d->ctx_->search_paths); + ctx->file_finder = d->ctx_->file_finder; + ctx->file_finder_legacy = d->ctx_->file_finder_legacy; + ctx->file_finder_user_data = d->ctx_->file_finder_user_data; + } + bool usePROJ4InitRules = d->usePROJ4InitRules_; if (!usePROJ4InitRules) { - PJ_CONTEXT *ctx = proj_context_create(); - if (ctx) { - usePROJ4InitRules = proj_context_get_use_proj4_init_rules( - ctx, FALSE) == TRUE; - proj_context_destroy(ctx); - } + usePROJ4InitRules = + proj_context_get_use_proj4_init_rules(ctx, FALSE) == TRUE; } if (!usePROJ4InitRules) { throw ParsingException("init=epsg:/init=IGNF: syntax not " "supported in non-PROJ4 emulation mode"); } - PJ_CONTEXT *ctx = proj_context_create(); char unused[256]; std::string initname(stepName); initname.resize(initname.find(':')); int file_found = pj_find_file(ctx, initname.c_str(), unused, sizeof(unused)); - proj_context_destroy(ctx); + if (!file_found) { auto obj = createFromUserInput(stepName, d->dbContext_, true); auto crs = dynamic_cast<CRS *>(obj.get()); @@ -8790,19 +8818,19 @@ PROJStringParser::createFromPROJString(const std::string &projString) { } } - paralist *init = pj_mkparam(("init=" + d->steps_[0].name).c_str()); - if (!init) { + auto ctx = d->ctx_ ? d->ctx_ : proj_context_create(); + if (!ctx) { throw ParsingException("out of memory"); } - PJ_CONTEXT *ctx = d->ctx_ ? d->ctx_ : proj_context_create(); - if (!ctx) { - pj_dealloc(init); + PJContextHolder contextHolder(ctx, ctx != d->ctx_); + + paralist *init = pj_mkparam(("init=" + d->steps_[0].name).c_str()); + if (!init) { throw ParsingException("out of memory"); } + ctx->projStringParserCreateFromPROJStringRecursionCounter++; paralist *list = pj_expand_init(ctx, init); - if (ctx != d->ctx_) { - proj_context_destroy(ctx); - } + ctx->projStringParserCreateFromPROJStringRecursionCounter--; if (!list) { pj_dealloc(init); throw ParsingException("cannot expand " + projString); @@ -8933,18 +8961,14 @@ PROJStringParser::createFromPROJString(const std::string &projString) { proj_log_func(pj_context, &logger, Logger::log); proj_context_use_proj4_init_rules(pj_context, d->usePROJ4InitRules_); } - if (d->ctx_) { - d->ctx_->curStringInCreateFromPROJString = projString; - } + pj_context->projStringParserCreateFromPROJStringRecursionCounter++; auto log_level = proj_log_level(pj_context, PJ_LOG_NONE); auto pj = pj_create_internal( pj_context, (projString.find("type=crs") != std::string::npos ? projString + " +disable_grid_presence_check" : projString) .c_str()); - if (d->ctx_) { - d->ctx_->curStringInCreateFromPROJString.clear(); - } + pj_context->projStringParserCreateFromPROJStringRecursionCounter--; valid = pj != nullptr; proj_log_level(pj_context, log_level); diff --git a/src/proj_internal.h b/src/proj_internal.h index 761746c1..4a126e98 100644 --- a/src/proj_internal.h +++ b/src/proj_internal.h @@ -706,7 +706,7 @@ struct projCtx_t { const char* (*file_finder) (PJ_CONTEXT *, const char*, void* user_data) = nullptr; void* file_finder_user_data = nullptr; - std::string curStringInCreateFromPROJString{}; + int projStringParserCreateFromPROJStringRecursionCounter = 0; // to avoid potential infinite recursion in PROJStringParser::createFromPROJString() projCtx_t() = default; projCtx_t(const projCtx_t&); |
