mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Fix memory corruption/crashes when events in extensions had errors (#7050)
This commit is contained in:
@@ -14,10 +14,10 @@
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief
|
||||
* \brief
|
||||
*/
|
||||
class GD_CORE_API ProjectDiagnostic {
|
||||
public:
|
||||
public:
|
||||
enum ErrorType {
|
||||
UndeclaredVariable,
|
||||
MissingBehavior,
|
||||
@@ -25,12 +25,17 @@ public:
|
||||
MismatchedObjectType,
|
||||
};
|
||||
|
||||
ProjectDiagnostic(ErrorType type_, const gd::String &message_,
|
||||
ProjectDiagnostic(ErrorType type_,
|
||||
const gd::String &message_,
|
||||
const gd::String &actualValue_,
|
||||
const gd::String &expectedValue_, const gd::String &objectName_ = "")
|
||||
: type(type_), message(message_), actualValue(actualValue_), expectedValue(expectedValue_),
|
||||
objectName(objectName_){};
|
||||
virtual ~ProjectDiagnostic(){};
|
||||
const gd::String &expectedValue_,
|
||||
const gd::String &objectName_ = "")
|
||||
: type(type_),
|
||||
message(message_),
|
||||
actualValue(actualValue_),
|
||||
expectedValue(expectedValue_),
|
||||
objectName(objectName_) {};
|
||||
virtual ~ProjectDiagnostic() {};
|
||||
|
||||
ErrorType GetType() const { return type; };
|
||||
const gd::String &GetMessage() const { return message; }
|
||||
@@ -38,7 +43,7 @@ public:
|
||||
const gd::String &GetActualValue() const { return actualValue; }
|
||||
const gd::String &GetExpectedValue() const { return expectedValue; }
|
||||
|
||||
private:
|
||||
private:
|
||||
ErrorType type;
|
||||
gd::String message;
|
||||
gd::String objectName;
|
||||
@@ -47,12 +52,12 @@ private:
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief
|
||||
* \brief
|
||||
*/
|
||||
class GD_CORE_API DiagnosticReport {
|
||||
public:
|
||||
DiagnosticReport(){};
|
||||
virtual ~DiagnosticReport(){};
|
||||
public:
|
||||
DiagnosticReport() {};
|
||||
virtual ~DiagnosticReport() {};
|
||||
|
||||
void Add(const gd::ProjectDiagnostic &projectDiagnostic) {
|
||||
projectDiagnostics.push_back(
|
||||
@@ -67,32 +72,39 @@ public:
|
||||
|
||||
const gd::String &GetSceneName() const { return sceneName; }
|
||||
|
||||
void SetSceneName(const gd::String &sceneName_) {
|
||||
sceneName = sceneName_;
|
||||
void SetSceneName(const gd::String &sceneName_) { sceneName = sceneName_; }
|
||||
|
||||
void LogAllDiagnostics() {
|
||||
for (auto &diagnostic : projectDiagnostics) {
|
||||
std::cout << diagnostic->GetMessage()
|
||||
<< "(object: " << diagnostic->GetObjectName()
|
||||
<< ", actual value: " << diagnostic->GetActualValue()
|
||||
<< ", expected value: " << diagnostic->GetExpectedValue() << ")"
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
std::vector<std::unique_ptr<gd::ProjectDiagnostic>> projectDiagnostics;
|
||||
gd::String sceneName;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief
|
||||
* \brief
|
||||
*/
|
||||
class GD_CORE_API WholeProjectDiagnosticReport {
|
||||
public:
|
||||
WholeProjectDiagnosticReport(){};
|
||||
virtual ~WholeProjectDiagnosticReport(){};
|
||||
public:
|
||||
WholeProjectDiagnosticReport() {};
|
||||
virtual ~WholeProjectDiagnosticReport() {};
|
||||
|
||||
const DiagnosticReport &Get(std::size_t index) const {
|
||||
return *diagnosticReports[index].get();
|
||||
};
|
||||
|
||||
void Clear() {
|
||||
diagnosticReports.clear();
|
||||
};
|
||||
void Clear() { diagnosticReports.clear(); };
|
||||
|
||||
DiagnosticReport& AddNewDiagnosticReportForScene(const gd::String &sceneName) {
|
||||
DiagnosticReport &AddNewDiagnosticReportForScene(
|
||||
const gd::String &sceneName) {
|
||||
auto diagnosticReport = gd::make_unique<gd::DiagnosticReport>();
|
||||
diagnosticReport->SetSceneName(sceneName);
|
||||
diagnosticReports.push_back(std::move(diagnosticReport));
|
||||
@@ -102,7 +114,7 @@ public:
|
||||
std::size_t Count() const { return diagnosticReports.size(); };
|
||||
|
||||
bool HasAnyIssue() {
|
||||
for (auto& diagnosticReport : diagnosticReports) {
|
||||
for (auto &diagnosticReport : diagnosticReports) {
|
||||
if (diagnosticReport->Count() > 0) {
|
||||
return true;
|
||||
}
|
||||
@@ -110,8 +122,8 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
std::vector<std::unique_ptr<gd::DiagnosticReport>> diagnosticReports;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
} // namespace gd
|
||||
|
@@ -345,14 +345,14 @@ gd::String EventsCodeGenerator::GenerateConditionCode(
|
||||
gd::ProjectDiagnostic projectDiagnostic(
|
||||
gd::ProjectDiagnostic::ErrorType::UnknownObject, "",
|
||||
objectInParameter, "");
|
||||
diagnosticReport->Add(projectDiagnostic);
|
||||
if (diagnosticReport) diagnosticReport->Add(projectDiagnostic);
|
||||
return "/* Unknown object - skipped. */";
|
||||
} else if (!expectedObjectType.empty() &&
|
||||
actualObjectType != expectedObjectType) {
|
||||
gd::ProjectDiagnostic projectDiagnostic(
|
||||
gd::ProjectDiagnostic::ErrorType::MismatchedObjectType, "",
|
||||
actualObjectType, expectedObjectType, objectInParameter);
|
||||
diagnosticReport->Add(projectDiagnostic);
|
||||
if (diagnosticReport) diagnosticReport->Add(projectDiagnostic);
|
||||
return "/* Mismatched object type - skipped. */";
|
||||
}
|
||||
}
|
||||
@@ -509,7 +509,7 @@ void EventsCodeGenerator::CheckBehaviorParameters(
|
||||
gd::ProjectDiagnostic projectDiagnostic(
|
||||
gd::ProjectDiagnostic::ErrorType::MissingBehavior, "",
|
||||
actualBehaviorType, expectedBehaviorType, lastObjectName);
|
||||
diagnosticReport->Add(projectDiagnostic);
|
||||
if (diagnosticReport) diagnosticReport->Add(projectDiagnostic);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -567,14 +567,14 @@ gd::String EventsCodeGenerator::GenerateActionCode(
|
||||
gd::ProjectDiagnostic projectDiagnostic(
|
||||
gd::ProjectDiagnostic::ErrorType::UnknownObject, "",
|
||||
objectInParameter, "");
|
||||
diagnosticReport->Add(projectDiagnostic);
|
||||
if (diagnosticReport) diagnosticReport->Add(projectDiagnostic);
|
||||
return "/* Unknown object - skipped. */";
|
||||
} else if (!expectedObjectType.empty() &&
|
||||
actualObjectType != expectedObjectType) {
|
||||
gd::ProjectDiagnostic projectDiagnostic(
|
||||
gd::ProjectDiagnostic::ErrorType::MismatchedObjectType, "",
|
||||
actualObjectType, expectedObjectType, objectInParameter);
|
||||
diagnosticReport->Add(projectDiagnostic);
|
||||
if (diagnosticReport) diagnosticReport->Add(projectDiagnostic);
|
||||
return "/* Mismatched object type - skipped. */";
|
||||
}
|
||||
}
|
||||
|
@@ -21,13 +21,13 @@
|
||||
#include "GDCore/Project/EventsBasedBehavior.h"
|
||||
#include "GDCore/Project/EventsBasedObject.h"
|
||||
#include "GDCore/Project/EventsFunction.h"
|
||||
#include "GDCore/Project/EventsFunctionsExtension.h"
|
||||
#include "GDCore/Project/ExternalEvents.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Object.h"
|
||||
#include "GDCore/Project/ObjectsContainer.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/PropertiesContainer.h"
|
||||
#include "GDCore/Project/EventsFunctionsExtension.h"
|
||||
#include "GDJS/Events/CodeGeneration/BehaviorCodeGenerator.h"
|
||||
#include "GDJS/Events/CodeGeneration/EventsCodeGenerator.h"
|
||||
#include "GDJS/Extensions/JsPlatform.h"
|
||||
@@ -130,19 +130,27 @@ gd::String EventsCodeGenerator::GenerateEventsFunctionCode(
|
||||
std::set<gd::String>& includeFiles,
|
||||
bool compilationForRuntime) {
|
||||
gd::ObjectsContainer parameterObjectsAndGroups;
|
||||
auto projectScopedContainers =
|
||||
gd::ProjectScopedContainers::MakeNewProjectScopedContainersForFreeEventsFunction(
|
||||
project, eventsFunctionsExtension, eventsFunction, parameterObjectsAndGroups);
|
||||
auto projectScopedContainers = gd::ProjectScopedContainers::
|
||||
MakeNewProjectScopedContainersForFreeEventsFunction(
|
||||
project,
|
||||
eventsFunctionsExtension,
|
||||
eventsFunction,
|
||||
parameterObjectsAndGroups);
|
||||
|
||||
EventsCodeGenerator codeGenerator(projectScopedContainers);
|
||||
codeGenerator.SetCodeNamespace(codeNamespace);
|
||||
codeGenerator.SetGenerateCodeForRuntime(compilationForRuntime);
|
||||
|
||||
gd::DiagnosticReport diagnosticReport;
|
||||
codeGenerator.SetDiagnosticReport(&diagnosticReport);
|
||||
|
||||
gd::String output = GenerateEventsListCompleteFunctionCode(
|
||||
codeGenerator,
|
||||
codeGenerator.GetCodeNamespaceAccessor() + "func",
|
||||
codeGenerator.GenerateEventsFunctionParameterDeclarationsList(
|
||||
eventsFunction.GetParametersForEvents(eventsFunctionsExtension), 0, true),
|
||||
eventsFunction.GetParametersForEvents(eventsFunctionsExtension),
|
||||
0,
|
||||
true),
|
||||
codeGenerator.GenerateFreeEventsFunctionContext(
|
||||
eventsFunctionsExtension,
|
||||
eventsFunction,
|
||||
@@ -151,6 +159,15 @@ gd::String EventsCodeGenerator::GenerateEventsFunctionCode(
|
||||
"",
|
||||
codeGenerator.GenerateEventsFunctionReturn(eventsFunction));
|
||||
|
||||
// TODO: the editor should pass the diagnostic report and display it to the
|
||||
// user. For now, display it in the console.
|
||||
if (diagnosticReport.Count() > 0) {
|
||||
std::cout << "Diagnostics when generating events function code ("
|
||||
<< eventsFunctionsExtension.GetName() << ", "
|
||||
<< eventsFunction.GetName() << "):" << std::endl;
|
||||
diagnosticReport.LogAllDiagnostics();
|
||||
}
|
||||
|
||||
includeFiles.insert(codeGenerator.GetIncludeFiles().begin(),
|
||||
codeGenerator.GetIncludeFiles().end());
|
||||
return output;
|
||||
@@ -167,17 +184,22 @@ gd::String EventsCodeGenerator::GenerateBehaviorEventsFunctionCode(
|
||||
const gd::String& preludeCode,
|
||||
std::set<gd::String>& includeFiles,
|
||||
bool compilationForRuntime) {
|
||||
|
||||
gd::ObjectsContainer parameterObjectsContainers;
|
||||
auto projectScopedContainers = gd::ProjectScopedContainers::
|
||||
MakeNewProjectScopedContainersForBehaviorEventsFunction(
|
||||
project, eventsFunctionsExtension, eventsBasedBehavior,
|
||||
eventsFunction, parameterObjectsContainers);
|
||||
project,
|
||||
eventsFunctionsExtension,
|
||||
eventsBasedBehavior,
|
||||
eventsFunction,
|
||||
parameterObjectsContainers);
|
||||
|
||||
EventsCodeGenerator codeGenerator(projectScopedContainers);
|
||||
codeGenerator.SetCodeNamespace(codeNamespace);
|
||||
codeGenerator.SetGenerateCodeForRuntime(compilationForRuntime);
|
||||
|
||||
gd::DiagnosticReport diagnosticReport;
|
||||
codeGenerator.SetDiagnosticReport(&diagnosticReport);
|
||||
|
||||
// Generate the code setting up the context of the function.
|
||||
gd::String fullPreludeCode =
|
||||
preludeCode + "\n" + "var that = this;\n" +
|
||||
@@ -216,6 +238,15 @@ gd::String EventsCodeGenerator::GenerateBehaviorEventsFunctionCode(
|
||||
"",
|
||||
codeGenerator.GenerateEventsFunctionReturn(eventsFunction));
|
||||
|
||||
// TODO: the editor should pass the diagnostic report and display it to the
|
||||
// user. For now, display it in the console.
|
||||
if (diagnosticReport.Count() > 0) {
|
||||
std::cout << "Diagnostics when generating behavior code ("
|
||||
<< eventsBasedBehavior.GetName() << ", "
|
||||
<< eventsFunction.GetName() << "):" << std::endl;
|
||||
diagnosticReport.LogAllDiagnostics();
|
||||
}
|
||||
|
||||
includeFiles.insert(codeGenerator.GetIncludeFiles().begin(),
|
||||
codeGenerator.GetIncludeFiles().end());
|
||||
return output;
|
||||
@@ -233,17 +264,22 @@ gd::String EventsCodeGenerator::GenerateObjectEventsFunctionCode(
|
||||
const gd::String& endingCode,
|
||||
std::set<gd::String>& includeFiles,
|
||||
bool compilationForRuntime) {
|
||||
|
||||
gd::ObjectsContainer parameterObjectsContainers;
|
||||
auto projectScopedContainers = gd::ProjectScopedContainers::
|
||||
MakeNewProjectScopedContainersForObjectEventsFunction(
|
||||
project, eventsFunctionsExtension, eventsBasedObject,
|
||||
eventsFunction, parameterObjectsContainers);
|
||||
project,
|
||||
eventsFunctionsExtension,
|
||||
eventsBasedObject,
|
||||
eventsFunction,
|
||||
parameterObjectsContainers);
|
||||
|
||||
EventsCodeGenerator codeGenerator(projectScopedContainers);
|
||||
codeGenerator.SetCodeNamespace(codeNamespace);
|
||||
codeGenerator.SetGenerateCodeForRuntime(compilationForRuntime);
|
||||
|
||||
gd::DiagnosticReport diagnosticReport;
|
||||
codeGenerator.SetDiagnosticReport(&diagnosticReport);
|
||||
|
||||
// Generate the code setting up the context of the function.
|
||||
gd::String fullPreludeCode =
|
||||
preludeCode + "\n" + "var that = this;\n" +
|
||||
@@ -258,8 +294,7 @@ gd::String EventsCodeGenerator::GenerateObjectEventsFunctionCode(
|
||||
"var Object = Hashtable.newFrom({Object: thisObjectList});\n";
|
||||
|
||||
// Add child-objects
|
||||
for (auto &childObject :
|
||||
eventsBasedObject.GetObjects().GetObjects()) {
|
||||
for (auto& childObject : eventsBasedObject.GetObjects().GetObjects()) {
|
||||
// child-object are never picked because they are not parameters.
|
||||
const auto& childName = ManObjListName(childObject->GetName());
|
||||
fullPreludeCode += "var this" + childName +
|
||||
@@ -293,6 +328,15 @@ gd::String EventsCodeGenerator::GenerateObjectEventsFunctionCode(
|
||||
endingCode,
|
||||
codeGenerator.GenerateEventsFunctionReturn(eventsFunction));
|
||||
|
||||
// TODO: the editor should pass the diagnostic report and display it to the
|
||||
// user. For now, display it in the console.
|
||||
if (diagnosticReport.Count() > 0) {
|
||||
std::cout << "Diagnostics when generating object code ("
|
||||
<< eventsBasedObject.GetName() << ", " << eventsFunction.GetName()
|
||||
<< "):" << std::endl;
|
||||
diagnosticReport.LogAllDiagnostics();
|
||||
}
|
||||
|
||||
includeFiles.insert(codeGenerator.GetIncludeFiles().begin(),
|
||||
codeGenerator.GetIncludeFiles().end());
|
||||
return output;
|
||||
@@ -424,8 +468,7 @@ gd::String EventsCodeGenerator::GenerateObjectEventsFunctionContext(
|
||||
ConvertToStringExplicit(thisObjectName) + ": thisObjectList\n";
|
||||
|
||||
// Add child-objects
|
||||
for (auto &childObject :
|
||||
eventsBasedObject.GetObjects().GetObjects()) {
|
||||
for (auto& childObject : eventsBasedObject.GetObjects().GetObjects()) {
|
||||
const auto& childName = ManObjListName(childObject->GetName());
|
||||
// child-object are never picked because they are not parameters.
|
||||
objectsGettersMap += ", " +
|
||||
@@ -458,8 +501,8 @@ gd::String EventsCodeGenerator::GenerateEventsFunctionContext(
|
||||
const gd::String& thisObjectName,
|
||||
const gd::String& thisBehaviorName) {
|
||||
const auto& extensionName = eventsFunctionsExtension.GetName();
|
||||
const auto ¶meters = eventsFunction.GetParametersForEvents(
|
||||
eventsFunctionsContainer);
|
||||
const auto& parameters =
|
||||
eventsFunction.GetParametersForEvents(eventsFunctionsContainer);
|
||||
|
||||
// When running in the context of a function generated from events, we
|
||||
// need some indirection to deal with objects, behaviors and parameters in
|
||||
@@ -514,8 +557,9 @@ gd::String EventsCodeGenerator::GenerateEventsFunctionContext(
|
||||
}
|
||||
}
|
||||
|
||||
const gd::String async =
|
||||
eventsFunction.IsAsync() ? " task: new gdjs.ManuallyResolvableTask(),\n" : "";
|
||||
const gd::String async = eventsFunction.IsAsync()
|
||||
? " task: new gdjs.ManuallyResolvableTask(),\n"
|
||||
: "";
|
||||
|
||||
return gd::String("var eventsFunctionContext = {\n") +
|
||||
// The async task, if there is one
|
||||
@@ -875,8 +919,9 @@ gd::String EventsCodeGenerator::GenerateObjectAction(
|
||||
if (instrInfos.codeExtraInformation.type == "number" ||
|
||||
instrInfos.codeExtraInformation.type == "string" ||
|
||||
// Boolean actions declared with addExpressionAndConditionAndAction uses
|
||||
// MutatorAndOrAccessor even though they don't declare an operator parameter.
|
||||
// Boolean operators are only used with SetMutators or SetCustomCodeGenerator.
|
||||
// MutatorAndOrAccessor even though they don't declare an operator
|
||||
// parameter. Boolean operators are only used with SetMutators or
|
||||
// SetCustomCodeGenerator.
|
||||
(instrInfos.codeExtraInformation.type == "boolean" &&
|
||||
instrInfos.codeExtraInformation.accessType ==
|
||||
gd::InstructionMetadata::ExtraInformation::AccessType::Mutators)) {
|
||||
@@ -942,8 +987,9 @@ gd::String EventsCodeGenerator::GenerateBehaviorAction(
|
||||
if (instrInfos.codeExtraInformation.type == "number" ||
|
||||
instrInfos.codeExtraInformation.type == "string" ||
|
||||
// Boolean actions declared with addExpressionAndConditionAndAction uses
|
||||
// MutatorAndOrAccessor even though they don't declare an operator parameter.
|
||||
// Boolean operators are only used with SetMutators or SetCustomCodeGenerator.
|
||||
// MutatorAndOrAccessor even though they don't declare an operator
|
||||
// parameter. Boolean operators are only used with SetMutators or
|
||||
// SetCustomCodeGenerator.
|
||||
(instrInfos.codeExtraInformation.type == "boolean" &&
|
||||
instrInfos.codeExtraInformation.accessType ==
|
||||
gd::InstructionMetadata::ExtraInformation::AccessType::Mutators)) {
|
||||
@@ -1311,7 +1357,7 @@ gd::String EventsCodeGenerator::GenerateGetVariable(
|
||||
if (scope == ANY_VARIABLE) {
|
||||
const auto variablesContainersList =
|
||||
GetProjectScopedContainers().GetVariablesContainersList();
|
||||
const auto &variablesContainer =
|
||||
const auto& variablesContainer =
|
||||
variablesContainersList.GetVariablesContainerFromVariableName(
|
||||
variableName);
|
||||
const auto sourceType = variablesContainer.GetSourceType();
|
||||
@@ -1327,12 +1373,13 @@ gd::String EventsCodeGenerator::GenerateGetVariable(
|
||||
variablesContainersList.GetLocalVariablesContainerPosition(
|
||||
variablesContainer);
|
||||
output = GenerateLocalVariablesStackAccessor() + "[" +
|
||||
gd::String::From(localVariablesIndex) + "]";
|
||||
gd::String::From(localVariablesIndex) + "]";
|
||||
} else if (sourceType ==
|
||||
gd::VariablesContainer::SourceType::ExtensionGlobal) {
|
||||
gd::VariablesContainer::SourceType::ExtensionGlobal) {
|
||||
variables = &variablesContainer;
|
||||
output = "eventsFunctionContext.globalVariablesForExtension";
|
||||
} else if (sourceType == gd::VariablesContainer::SourceType::ExtensionScene) {
|
||||
} else if (sourceType ==
|
||||
gd::VariablesContainer::SourceType::ExtensionScene) {
|
||||
variables = &variablesContainer;
|
||||
output = "eventsFunctionContext.sceneVariablesForExtension";
|
||||
}
|
||||
@@ -1371,17 +1418,13 @@ gd::String EventsCodeGenerator::GenerateGetVariable(
|
||||
|
||||
if (HasProjectAndLayout()) {
|
||||
if (GetLayout().GetObjects().HasObjectNamed(
|
||||
objectName)) // We check first layout's objects' list.
|
||||
variables = &GetLayout()
|
||||
.GetObjects()
|
||||
.GetObject(objectName)
|
||||
.GetVariables();
|
||||
objectName)) // We check first layout's objects' list.
|
||||
variables =
|
||||
&GetLayout().GetObjects().GetObject(objectName).GetVariables();
|
||||
else if (GetProject().GetObjects().HasObjectNamed(
|
||||
objectName)) // Then the global objects list.
|
||||
variables = &GetProject()
|
||||
.GetObjects()
|
||||
.GetObject(objectName)
|
||||
.GetVariables();
|
||||
objectName)) // Then the global objects list.
|
||||
variables =
|
||||
&GetProject().GetObjects().GetObject(objectName).GetVariables();
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user