Sign in to follow this  

member functions that return an object gets invalid parameter

This topic is 4351 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

As before, I am compiling with AS_ALLOW_UNSAFE_REFERENCES. It crashes when calling foo_member_fun_one. free_fun and foo_member_fun_two both work fine. The problem seems to be that when a member function returns an object the first parameter is corrupted. The this pointer is valid. But the string reference is not.
#include "angelscript.h"
#include <string>
#include <iostream>

struct Foo 
{
	Foo() {}
	~Foo() {}
	Foo(const Foo& rhs) {}
	Foo& operator=(const Foo& rhs) { return *this; }
};

//THIS CRASHES.
std::string foo_member_fun_one(const std::string& in, Foo* thisp)
{
	std::cout << "foo_member_fun_one: " << in << "\n";
	return in;
}

void foo_member_fun_two(const std::string& in, Foo* thisp)
{
	std::cout << "foo_member_fun_two: " << in << "\n";
}

std::string free_fun(const std::string& in)
{
	std::cout << "free_fun: " << in << "\n";
	return in;
}

void ConstructFoo(Foo* ptr) { new (ptr) Foo(); }
void CopyConstructFoo(const Foo& rhs, Foo* ptr) { new (ptr) Foo(rhs); }
void DestroyFoo(Foo* ptr) { ptr->~Foo(); } 
Foo& AssignFoo(const Foo& rhs, Foo* ptr) { return (*ptr) = rhs; }

void ConstructString(std::string* ptr) { new (ptr) std::string(); }
void CopyConstructString(const std::string& rhs, std::string* ptr) { new (ptr) std::string(rhs); }
void DestroyString(std::string* ptr) { ptr->~basic_string(); } 
std::string& AssignString(const std::string& rhs, std::string* ptr) { return (*ptr) = rhs; }

std::string StringFactory(unsigned int length, const char *s)
	{
		std::cout << "StringFactory: " << std::string(s,length) << "\n";
		return std::string(s,length);
	}

int main(int argc, char* argv[])
{
	asIScriptEngine* engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
	int error_code = 0;
	
	std::cout << "Registering Foo. ";
	error_code = engine->RegisterObjectType("Foo",sizeof(Foo),asOBJ_CLASS_CDA);
	if (error_code < 0) std::cout << "Error: " << error_code;

	std::cout << "\nRegistering Foo constructor. ";
	error_code = engine->RegisterObjectBehaviour("Foo",
		asBEHAVE_CONSTRUCT,
		"void constructor()",
		asFUNCTION(ConstructFoo),
		asCALL_CDECL_OBJLAST);	
	if (error_code < 0) std::cout << "Error: " << error_code;

	std::cout << "\nRegistering Foo destructor. ";	
	error_code = engine->RegisterObjectBehaviour("Foo",
		asBEHAVE_DESTRUCT,
		"void destructor()",
		asFUNCTION(DestroyFoo),
		asCALL_CDECL_OBJLAST);	
	if (error_code < 0) std::cout << "Error: " << error_code;

	std::cout << "\nRegistering Foo operator=. ";
	error_code = engine->RegisterObjectBehaviour("Foo",
		asBEHAVE_ASSIGNMENT,
		"Foo& op_assign(const Foo&)",
		asFUNCTION(AssignFoo),
		asCALL_CDECL_OBJLAST);	
	if (error_code < 0) std::cout << "Error: " << error_code;

	std::cout << "\nRegistering Foo copy constructor. ";
	error_code = engine->RegisterObjectBehaviour("Foo",
		asBEHAVE_CONSTRUCT,
		"void constructor(const Foo&)",
		asFUNCTION(CopyConstructFoo),
		asCALL_CDECL_OBJLAST);					
	if (error_code < 0) std::cout << "Error: " << error_code;

	std::cout << "\nRegistering string. ";
	error_code = engine->RegisterObjectType("string",sizeof(std::string),asOBJ_CLASS_CDA);
	if (error_code < 0) std::cout << "Error: " << error_code;

	std::cout << "\nRegistering string constructor. ";
	error_code = engine->RegisterObjectBehaviour("string",
		asBEHAVE_CONSTRUCT,
		"void constructor()",
		asFUNCTION(ConstructString),
		asCALL_CDECL_OBJLAST);	
	if (error_code < 0) std::cout << "Error: " << error_code;

	std::cout << "\nRegistering string destructor. ";	
	error_code = engine->RegisterObjectBehaviour("string",
		asBEHAVE_DESTRUCT,
		"void destructor()",
		asFUNCTION(DestroyString),
		asCALL_CDECL_OBJLAST);	
	if (error_code < 0) std::cout << "Error: " << error_code;

	std::cout << "\nRegistering string operator=. ";
	error_code = engine->RegisterObjectBehaviour("string",
		asBEHAVE_ASSIGNMENT,
		"string& op_assign(const string&)",
		asFUNCTION(AssignString),
		asCALL_CDECL_OBJLAST);	
	if (error_code < 0) std::cout << "Error: " << error_code;

	std::cout << "\nRegistering string copy constructor. ";
	error_code = engine->RegisterObjectBehaviour("string",
		asBEHAVE_CONSTRUCT,
		"void constructor(const string&)",
		asFUNCTION(CopyConstructString),
		asCALL_CDECL_OBJLAST);					
	if (error_code < 0) std::cout << "Error: " << error_code;

	std::cout << "\nRegistering string factory. ";
	error_code = engine->RegisterStringFactory("string",
		asFUNCTION(StringFactory),
		asCALL_CDECL);
	if (error_code < 0) std::cout << "Error: " << error_code;

	std::cout << "\nRegistering Foo member fun one. ";
	error_code = engine->RegisterObjectMethod("Foo",
		"string member_one(const string&)",
		asFUNCTION(foo_member_fun_one),
		asCALL_CDECL_OBJLAST);
	if (error_code < 0) std::cout << "Error: " << error_code;

	std::cout << "\nRegistering Foo member fun two. ";
	error_code = engine->RegisterObjectMethod("Foo",
		"void member_two(const string&)",
		asFUNCTION(foo_member_fun_two),
		asCALL_CDECL_OBJLAST);
	if (error_code < 0) std::cout << "Error: " << error_code;

	std::cout << "\nRegistering free fun. ";
	error_code = engine->RegisterGlobalFunction(
		"string free_fun(const string&)",
		asFUNCTION(free_fun),
		asCALL_CDECL);
	if (error_code < 0) std::cout << "Error: " << error_code;

	std::string script = "void test(Foo f) { free_fun(\"foo\"); f.member_two(\"foo\"); f.member_one(\"foo\"); }";
	engine->AddScriptSection(0,"test",script.c_str(),script.length());
	
	std::cout << "\nBuilding test script. ";
	error_code = engine->Build(0);
	if (error_code < 0) std::cout << "Error: " << error_code;

	std::cout << "\nGetting function id. ";
	int func_id = engine->GetFunctionIDByName(0,"test");
	if (func_id < 0) std::cout << error_code;

	asIScriptContext* ctx = engine->CreateContext();
	std::cout << "\nPreparing context. ";
	error_code = ctx->Prepare(func_id);
	if (error_code < 0) std::cout << "Error: " << error_code;

	Foo f;

	std::cout << "\nSetting parameter. ";
	error_code = ctx->SetArgObject(0,&f);
	if (error_code < 0) std::cout << "Error: " << error_code;

	std::cout << "\nCalling script.\n";
	error_code = ctx->Execute();
	if (error_code != asEXECUTION_FINISHED) std::cout << "Error: " << error_code;

	std::cout << "\n\nFin.";	

	return 0;
}

Share this post


Link to post
Share on other sites
I've ran into this issue also. Although I thought it was due to the way my environment was set up, the objects were being created in a dll, and being manipulated by angelscript which resides in the .exe

I traced the problem down to when angelscript calls the destructor on the object during a temporary copy of some sort, which I attributed to cross module boundary object lifetime issues.

My issue may however be unrelated.

Share this post


Link to post
Share on other sites
You may want to register the memory management functions with AngelScript if this is your problem. This can be done on both a global level and individually for each registered object type.

Doing this will make sure AngelScript uses the same heap for memory allocation as the application.

See the following functions for more info:

engine::SetCommonObjectMemoryFunctions()
engine::RegisterObjectBehaviour() with behaviours asBEHAVE_ALLOC and asBEHAVE_FREE

Share this post


Link to post
Share on other sites
In that case I was referring to Rain Dog. [wink]

Actually in your other thread you mentioned something that could be related to the memory management, so I intended the response for both of you. Mostly as something to think about.

I still pretend to test the problem you reported in this thread, but I haven't had the time to do so yet.

Share this post


Link to post
Share on other sites
In this context 'pretend to' is the same as 'intend to'. At least that is how I understand it. [wink]

Anyway, I found the bug. It's an old bug so I'm a bit surprised that it hasn't shown up before. On line 260 in as_callfunc_x86.cpp the function pointer is initialized incorrectly. It should be:


const t_CallCDeclObjRetByRef CallCDeclFunctionRetByRefObjLast = (t_CallCDeclObjRetByRef)CallCDeclFunctionRetByRefObjLast_impl;


Regards,
Andreas

[edit]Updated file name[/edit]

[Edited by - WitchLord on January 13, 2006 7:12:39 AM]

Share this post


Link to post
Share on other sites
And it works great. :) I can tell you why it wasn't noticed earlier; I'm actually doing something a bit wierd. I originally had an actual member function bound with asCALL_THISCALL. It worked fine then, and this is what most people do. I did something a little wierd after that - I had to insert code between the script and that member function call, so I did something like
[code]
string func(parms,thispointer)
{
//new code here...
thispointer->func(parms);
};

And it worked for awhile. Until I finished roughing it out and actually used the parameters. :/

Share this post


Link to post
Share on other sites

This topic is 4351 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this