aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEven Rouault <even.rouault@spatialys.com>2019-09-06 11:29:07 +0200
committerGitHub <noreply@github.com>2019-09-06 11:29:07 +0200
commit73ccf7e1ba2ba9e927c4eaef81f5237fb4f587b2 (patch)
tree7e6996f97af28d1fca89a47edc8bb3bb3c42a9e9
parentb7ed294cff05f42ef24a212c85a10106565eef35 (diff)
parent9c38babea4650a20ec94eff9ab644f5c84c89874 (diff)
downloadPROJ-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.cpp72
-rw-r--r--src/proj_internal.h2
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&);