Skip to content

Commit

Permalink
Limit max recursion for script importer and added a test.
Browse files Browse the repository at this point in the history
  • Loading branch information
tomuben committed Oct 11, 2024
1 parent 6739678 commit 3c66a0b
Show file tree
Hide file tree
Showing 8 changed files with 215 additions and 8 deletions.
2 changes: 1 addition & 1 deletion exaudfclient/base/javacontainer/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ cc_library(
name = "javacontainer",
srcs = [":javacontainer.cc", ":javacontainer.h", ":javacontainer_impl.cc", ":javacontainer_impl.h", ":dummy"],
hdrs = [":filter_swig_code_exascript_java_h", "exascript_java_jni_decl.h"],
deps = ["@ssl//:ssl","@java//:java", ":exascript_java", "//base/exaudflib:header",
deps = ["@java//:java", ":exascript_java", "//base/exaudflib:header",
"//base/utils:utils","//base/javacontainer/script_options:java_script_option_lines",
"//base/swig_factory:swig_factory_if"],
# copts= ["-O0","-fno-lto"],
Expand Down
2 changes: 1 addition & 1 deletion exaudfclient/base/javacontainer/script_options/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ cc_library(
srcs = [":parser.h", ":converter.h", ":converter.cc", ":parser_legacy.cc", ":extractor.cc",
":keywords.h", ":keywords.cc", ":checksum.h", ":checksum.cc", ":parser_ctpg.cc",
":parser_ctpg_script_importer.cc", ":parser_ctpg_script_importer.h"],
deps = ["//base/script_options_parser/legacy:script_option_lines_parser_legacy",
deps = ["@ssl//:ssl", "//base/script_options_parser/legacy:script_option_lines_parser_legacy",
"//base/script_options_parser/ctpg:script_option_lines_parser_ctpg", "//base/utils:utils",
"//base/exaudflib:header", "//base/exaudflib:exaudflib-deps", "//base/swig_factory:swig_factory_if",
"//base/script_options_parser:exception"],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,19 @@ ScriptImporter::ScriptImporter(SwigFactory & swigFactory, Keywords & keywords)
, m_metaData()
, m_keywords(keywords) {}

void ScriptImporter::importScript(std::string & scriptCode, ctpg_parser::options_map_t & options) {
void ScriptImporter::importScript(std::string & scriptCode,
ctpg_parser::options_map_t & options) {
importScript(scriptCode, options, 0);
}

void ScriptImporter::importScript(std::string & scriptCode,
ctpg_parser::options_map_t & options,
const size_t recursionDepth) {
const auto optionIt = options.find(std::string(m_keywords.importKeyword()));

if (recursionDepth >= cMaxRecursionDepth) {
throw std::runtime_error("F-UDF-CL-SL-JAVA-1633: Maximal recursion depth for importing scripts reached.");
}
if (optionIt != options.end()) {
m_importedScriptChecksums.addScript(scriptCode.c_str());
//Sort options from first in script to last in script
Expand All @@ -45,7 +56,7 @@ void ScriptImporter::importScript(std::string & scriptCode, ctpg_parser::options
for (const auto & option: optionIt->second) {
const char *importScriptCode = findImportScript(option.value);
std::string importScriptCodeStr;
if (m_importedScriptChecksums.addScript(importScriptCode)) {
if (m_importedScriptChecksums.addScript(importScriptCode) ) {
// Script has not been imported yet
// If this imported script contains %import statements
// they will be resolved in the next recursion.
Expand All @@ -56,7 +67,7 @@ void ScriptImporter::importScript(std::string & scriptCode, ctpg_parser::options
Utils::rethrow(ex, "F-UDF-CL-SL-JAVA-1630");
}
importScriptCodeStr.assign(importScriptCode);
importScript(importScriptCodeStr, newOptions);
importScript(importScriptCodeStr, newOptions, recursionDepth + 1);
}
ReplacedScripts replacedScript = {.script = std::move(importScriptCodeStr), .origPos = option.idx_in_source, .origLen = option.size };
replacedScripts.push_back(std::move(replacedScript));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,20 @@ class ScriptImporter {
public:
ScriptImporter(SwigFactory & swigFactory, Keywords & keywords);

void importScript(std::string & scriptCode,
ExecutionGraph::OptionsLineParser::CTPG::options_map_t & options);
void importScript(std::string & scriptCode, ExecutionGraph::OptionsLineParser::CTPG::options_map_t & options);

private:
const char* findImportScript(const std::string & scriptKey);
void importScript(std::string & scriptCode,
ExecutionGraph::OptionsLineParser::CTPG::options_map_t & options,
const size_t recursionDepth);
const char* findImportScript(const std::string & scriptKey);
private:
Checksum m_importedScriptChecksums;
SwigFactory & m_swigFactory;
std::unique_ptr<SWIGMetadataIf> m_metaData;
Keywords & m_keywords;
//The empirical maximal value for recursion depth is ~26000. So we choose 20000 to have a certain buffer.
const size_t cMaxRecursionDepth = 20000;
};

} //namespace CTPG
Expand Down
10 changes: 10 additions & 0 deletions exaudfclient/base/javacontainer/script_options/test/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

cc_test(
name = "java-script-options-tests",
srcs = ["ctpg_script_importer_test.cc", "swig_factory_test.cc", "swig_factory_test.h"],
deps = [
"//base/javacontainer/script_options:java_script_option_lines",
"@googletest//:gtest_main",
],
)

Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@

#include "include/gtest/gtest.h"
#include "gmock/gmock.h"
#include "base/javacontainer/script_options/parser_ctpg.h"

#include "base/javacontainer/script_options/test/swig_factory_test.h"
#include <string.h>

using namespace SWIGVMContainers::JavaScriptOptions;


static const char* sc_scriptName = "script";


void checkIndex(size_t currentIdx, const char* scriptKey) {
std::stringstream ss;
ss << sc_scriptName << currentIdx;
if (ss.str() != scriptKey) {
throw std::logic_error(std::string("Script Key does not match: '") + ss.str() + " != '" + scriptKey + "'");
}
}

const char* buildNewScriptCode(size_t currentIdx) {
std::stringstream ss;
ss << "%import " << sc_scriptName << currentIdx << ";something";
static std::string ret;
ret = ss.str();
return ret.c_str();
}

TEST(ScriptImporterTest, max_recursion_depth) {

size_t currentIdx = 0;
SwigFactoryTestImpl swigFactoryTest([&](const char* scriptKey) {
checkIndex(currentIdx, scriptKey);
return buildNewScriptCode(++currentIdx);
});
ScriptOptionLinesParserCTPG parser;

const std::string code = buildNewScriptCode(currentIdx);
parser.prepareScriptCode(code);
EXPECT_THROW({
try
{
parser.extractImportScripts(swigFactoryTest);
}
catch( const std::runtime_error& e )
{
//We need to deceive "find_duplicate_error_codes.sh" here
const std::string expectedError =
std::string("F-UDF-CL-SL-JAVA-") + "1633: Maximal recursion depth for importing scripts reached.";
EXPECT_STREQ( expectedError.c_str(), e.what());
throw;
}
}, std::runtime_error );
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#include "base/javacontainer/script_options/test/swig_factory_test.h"
#include "base/exaudflib/swig/swig_meta_data.h"

#include <stdexcept>

class NotImplemented : public std::logic_error
{
public:
NotImplemented() : std::logic_error("Function not yet implemented") { };
NotImplemented(const std::string funcName) : std::logic_error("Function " + funcName + " not yet implemented") { };
};

class SWIGMetadataTest : public SWIGVMContainers::SWIGMetadataIf {

public:
SWIGMetadataTest(std::function<const char*(const char*)> callback): m_callback(callback) {}
virtual const char* databaseName() { throw NotImplemented("databaseName"); return nullptr;}
virtual const char* databaseVersion() { throw NotImplemented("databaseVersion"); return nullptr;}
virtual const char* scriptName() { throw NotImplemented("scriptName"); return nullptr;}
virtual const char* scriptSchema() { throw NotImplemented("scriptSchema"); return nullptr;}
virtual const char* currentUser() { throw NotImplemented("currentUser"); return nullptr;}
virtual const char* scopeUser() { throw NotImplemented("scopeUser"); return nullptr;}
virtual const char* currentSchema() { throw NotImplemented("currentSchema"); return nullptr;}
virtual const char* scriptCode() { throw NotImplemented("scriptCode"); return nullptr;}
virtual const unsigned long long sessionID() { throw NotImplemented("sessionID"); return 0;}
virtual const char *sessionID_S() { throw NotImplemented("sessionID_S"); return nullptr;}
virtual const unsigned long statementID() { throw NotImplemented("statementID"); return 0;}
virtual const unsigned int nodeCount() { throw NotImplemented("nodeCount"); return 0;}
virtual const unsigned int nodeID() { throw NotImplemented("nodeID"); return 0;}
virtual const unsigned long long vmID() { throw NotImplemented("vmID"); return 0;}
virtual const unsigned long long memoryLimit() { throw NotImplemented("memoryLimit"); return 0;}
virtual const SWIGVMContainers::VMTYPE vmType() {
throw NotImplemented("vmType");
return SWIGVMContainers::VM_UNSUPPORTED;
}
virtual const char *vmID_S() { throw NotImplemented("vmID_S"); return nullptr;}
virtual const ExecutionGraph::ConnectionInformationWrapper* connectionInformation(const char* connection_name) {
throw NotImplemented("connectionInformation"); return nullptr;
}
virtual const char* moduleContent(const char* name) {
return m_callback(name);
}
virtual const unsigned int inputColumnCount() { throw NotImplemented("inputColumnCount"); return 0;}
virtual const char *inputColumnName(unsigned int col) {
throw NotImplemented("inputColumnName");
return nullptr;
}
virtual const SWIGVMContainers::SWIGVM_datatype_e inputColumnType(unsigned int col) {
throw NotImplemented("inputColumnType");
return SWIGVMContainers::UNSUPPORTED;
}
virtual const char *inputColumnTypeName(unsigned int col) {
throw NotImplemented("inputColumnTypeName"); return nullptr;
}
virtual const unsigned int inputColumnSize(unsigned int col) {
throw NotImplemented("inputColumnSize"); return 0;
}
virtual const unsigned int inputColumnPrecision(unsigned int col) {
throw NotImplemented("inputColumnPrecision"); return 0;
}
virtual const unsigned int inputColumnScale(unsigned int col) {
throw NotImplemented("inputColumnScale"); return 0;
}
virtual const SWIGVMContainers::SWIGVM_itertype_e inputType() {
throw NotImplemented("inputType");
return SWIGVMContainers::EXACTLY_ONCE;
}
virtual const unsigned int outputColumnCount() { throw NotImplemented("outputColumnCount"); return 0;}
virtual const char *outputColumnName(unsigned int col) { throw NotImplemented("outputColumnName"); return nullptr;}
virtual const SWIGVMContainers::SWIGVM_datatype_e outputColumnType(unsigned int col) {
throw NotImplemented("outputColumnType");
return SWIGVMContainers::UNSUPPORTED;
}
virtual const char *outputColumnTypeName(unsigned int col) {
throw NotImplemented("outputColumnTypeName"); return nullptr;
}
virtual const unsigned int outputColumnSize(unsigned int col) {
throw NotImplemented("outputColumnSize"); return 0;
}
virtual const unsigned int outputColumnPrecision(unsigned int col) {
throw NotImplemented("outputColumnPrecision"); return 0;
}
virtual const unsigned int outputColumnScale(unsigned int col) {
throw NotImplemented("outputColumnScale"); return 0;
}
virtual const SWIGVMContainers::SWIGVM_itertype_e outputType() {
throw NotImplemented("outputType");
return SWIGVMContainers::EXACTLY_ONCE;
}
virtual const bool isEmittedColumn(unsigned int col) { throw NotImplemented("isEmittedColumn"); return false;}
virtual const char* checkException() { return nullptr;}
virtual const char* pluginLanguageName() { throw NotImplemented("pluginLanguageName"); return nullptr;}
virtual const char* pluginURI() { throw NotImplemented("pluginURI"); return nullptr;}
virtual const char* outputAddress() { throw NotImplemented("outputAddress"); return nullptr;}

private:
std::function<const char*(const char*)> m_callback;
};

SwigFactoryTestImpl::SwigFactoryTestImpl(std::function<const char*(const char*)> callback)
: m_callback(callback) {}

SWIGVMContainers::SWIGMetadataIf* SwigFactoryTestImpl::makeSwigMetadata() {
return new SWIGMetadataTest(m_callback);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#ifndef SWIG_FACTORY_TEST_H
#define SWIG_FACTORY_TEST_H 1

#include <string>
#include <map>
#include "base/swig_factory/swig_factory.h"
#include <functional>

struct SwigFactoryTestImpl : public SWIGVMContainers::SwigFactory {

SwigFactoryTestImpl(std::function<const char*(const char*)> callback);

virtual SWIGVMContainers::SWIGMetadataIf* makeSwigMetadata() override;

private:
std::function<const char*(const char*)> m_callback;
};


#endif //namespace SWIG_FACTORY_TEST_H

0 comments on commit 3c66a0b

Please sign in to comment.