Garbage data output on operator+ member

Started by
16 comments, last by BrianEmpson 12 years, 8 months ago
Hello,

I am currently troubleshooting an issue with my registered operator+ function returning garbage when it is used. I have not check the other operators I have defined yet for this same bug, this is the first.

Here is the test script:


void main()
{
dim2f video_res(800,600);
dim2f another_res(video_res);
dim2f total_res;
total_res = video_res + video_res;
string videoStr;
videoStr = "Video resolution: " + video_res.Width + "x" + video_res.Height + "\n";
print(videoStr);
videoStr = "Video resolution: " + another_res.Width + "x" + another_res.Height + "\n";
print(videoStr);
videoStr = "Total resolution: " + total_res.Width + "x" + total_res.Height + "\n";
print(videoStr);
total_res += total_res;
videoStr = "Total resolution: " + total_res.Width + "x" + total_res.Height + "\n";
print(videoStr);
}



Here is the output:

Video resolution: 800x600

Video resolution: 800x600

Total resolution: 0x3.74088e-014

Total resolution: 0x3.74088e-014[/quote]


Here are the registration statements:


//This code uses bindutils.h for the constructors...
engine->RegisterObjectType("dim2f", sizeof(dimension2df), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_CAK); assert( r >= 0 );

engine->RegisterObjectBehaviour("dim2f",asBEHAVE_CONSTRUCT,"void f()", asFUNCTION((Wrap::Construct<dimension2df>)), asCALL_CDECL_OBJLAST);
engine->RegisterObjectBehaviour("dim2f",asBEHAVE_CONSTRUCT,"void f(const dim2f &in)", asFUNCTION((Wrap::Construct1<dimension2df,dimension2df&>)),asCALL_CDECL_OBJLAST);
engine->RegisterObjectBehaviour("dim2f",asBEHAVE_CONSTRUCT,"void f(const vec2f &in)", asFUNCTION((Wrap::Construct1<dimension2df,vector2df&>)), asCALL_CDECL_OBJLAST);
engine->RegisterObjectBehaviour("dim2f",asBEHAVE_CONSTRUCT,"void f(f32 &in, f32 &in)", asFUNCTION((Wrap::Construct2<dimension2df,f32&,f32&>)), asCALL_CDECL_OBJLAST);
engine->RegisterObjectMethod("dim2f", "dim2f opAdd(const dim2f &in) const", asMETHODPR(dimension2df, operator+, (const dimension2df&) const, dimension2df), asCALL_THISCALL);
engine->RegisterObjectMethod("dim2f", "dim2f opAddAssign(const dim2f &in)", asMETHODPR(dimension2df, operator+=, (const dimension2df&), dimension2df&), asCALL_THISCALL);



Finally, here is the operator function itself:



//! Add two dimensions
dimension2d<T> operator+(const dimension2d<T>& other) const
{
return dimension2d<T>(Width+other.Width, Height+other.Height);
}



And the source file itself: http://irrlicht.sour..._8h_source.html

Any ideas as to what I did wrong? I suspect it is something to do with a misplaced '&' symbol, but I cannot find where...Any ideas?

Thanks for your help.
Advertisement
It is possible it is a problem with AngelScript. I'll investigate this.

However you don't seem to register the dimension2df::operator= method, i.e.:

engine->RegisterObjectMethod("dim2f", "dim2f &opAssign(const dim2f &in)", asMETHODPR(dimension2df, operator=, (const dimension2df &), dimension2df &), asCALL_THISCALL);
It really shouldn't be necessary to register it, as you registered the type as asOBJ_POD, but there might be a problem in AngelScript so if you could give it a try and let me know if it works it would help me identify the problem.

[EDIT] I tried to reproduce this problem, but wasn't able to. What compiler are you using and what is your operative system?

Can you set a break point in the operator+ method and check if the input is correct? That at least would help narrow down where the problem might be.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Here are all the registrations for that class:



//Object Methods
r = engine->RegisterObjectMethod("dim2f", "dim2f &opAssign(const dim2f &in)", asMETHODPR(dimension2df, operator =, (const dimension2df&), dimension2df&), asCALL_THISCALL);
assert(r >= 0);
r = engine->RegisterObjectMethod("dim2f", "dim2f &opAssign(const dim2u &in)", asMETHODPR(dimension2df, operator =, (const dimension2du&), dimension2df&), asCALL_THISCALL); assert(r >= 0);
r = engine->RegisterObjectMethod("dim2f", "dim2f &opAssign(const dim2i &in)", asMETHODPR(dimension2df, operator =, (const dimension2di&), dimension2df&), asCALL_THISCALL); assert(r >= 0);
r = engine->RegisterObjectMethod("dim2f", "bool opEquals(const dim2f &in) const", asMETHODPR(dimension2df, operator==, (const dimension2df&) const, bool), asCALL_THISCALL); assert(r >= 0);
r = engine->RegisterObjectMethod("dim2f", "bool opEquals(const vec2f &in) const", asMETHODPR(dimension2df, operator==, (const vector2df&) const, bool), asCALL_THISCALL); assert(r >= 0);
r = engine->RegisterObjectMethod("dim2f", "bool opNotEquals(const dim2f &in) const", asMETHODPR(dimension2df, operator!=, (const dimension2df&) const, bool), asCALL_THISCALL); assert(r >= 0);
r = engine->RegisterObjectMethod("dim2f", "bool opNotEquals(const vec2f &in) const", asMETHODPR(dimension2df, operator!=, (const vector2df&) const, bool), asCALL_THISCALL); assert(r >= 0);
r = engine->RegisterObjectMethod("dim2f", "dim2f opDivAssign(const f32 &in)", asMETHODPR(dimension2df, operator/=, (const f32&), dimension2df&), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("dim2f", "dim2f opDiv(const f32 &in) const", asMETHODPR(dimension2df, operator/, (const f32&) const, dimension2df), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("dim2f", "dim2f opMulAssign(const f32 &in) const", asMETHODPR(dimension2df, operator*=, (const f32&), dimension2df&), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("dim2f", "dim2f opMul(const f32 &in) const", asMETHODPR(dimension2df, operator*, (const f32&) const, dimension2df), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("dim2f", "dim2f opAddAssign(const dim2f &in)", asMETHODPR(dimension2df, operator+=, (const dimension2df&), dimension2df&), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("dim2f", "dim2f opSubAssign(const dim2f &in)", asMETHODPR(dimension2df, operator-=, (const dimension2df&), dimension2df&), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("dim2f", "dim2f opAdd(const dim2f &in) const", asMETHODPR(dimension2df, operator+, (const dimension2df&) const, dimension2df), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("dim2f", "dim2f set(const f32 &in,const f32 &in)", asMETHOD(dimension2df,set), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("dim2f", "f32 getArea() const", asMETHOD(dimension2df,getArea), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("dim2f", "dim2f getOptimalSize(bool &in,bool &in,bool &in,u32 &in) const", asMETHOD(dimension2df,getOptimalSize), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("dim2f", "dim2f getInterpolated(const dim2f &in, f32 &in) const", asMETHOD(dimension2df,getInterpolated),asCALL_THISCALL); assert( r >= 0 );



Because it is a template function I tried to overload the assign with all the reasonable dim2X variable types. It should pick the float when it tries to find the right function.

I am using CodeBlocks 10.5 with MinGW. Did you mean a break point on the script function itself? How would I do that? All the registrations are native, so there are no wrapper functions...
No, I meant a break point in the C++ method dimension2d<T>::operator+. When it stops there, check the this pointer and the argument to see if they have proper values.

OK, so the opAssign method is registered. Do the script work if you write the following?



dim2f video_res(800,600);

dim2f total_res;

total_res = video_res;

string videoStr;

videoStr = "Total resolution: " + total_res.Width + "x" + total_res.Height + "\n";

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

I think you have a comma in the wrong place in the registration of opAdd (you have it after the last const, instead of before).
@WitchLord:Here is the output from that script:

Total resolution: 800x600


I have attached a picture of the debugger watches. The 'other' variable is correctly set. *this has wrong values

opplustroubleshooting.png

@immortius:

I do not know where else I would place the comma without causing a compiler error? The compiler is very picky about the parameters.
Ok, so I halfway fixed the issue. I changed the registration function from:


r = engine->RegisterObjectMethod("dim2f", "dim2f opAdd(const dim2f &in) const", asMETHODPR(dimension2df, operator+, (const dimension2df&) const, dimension2df), asCALL_THISCALL);



To:


r = engine->RegisterObjectMethod("dim2f", "dim2f& opAdd(const dim2f &in) const", asMETHODPR(dimension2df, operator+, (const dimension2df&) const, dimension2df), asCALL_THISCALL);



And now I get the correct output:

opplustroubleshooting2.png


But I also get a SIGSEGV (segfault) at the constructor template from bindutils.h:

opplustroubleshooting3.png


I will rewrite my own constructors and see if I can pinpoint the problem.
I apologize if I am being too verbose in my troubleshooting efforts, I figured you'd want all the information possible. So I looked at how the constructor was receiving the arguments and tried twiddling around with the reference operators.

From this:

engine->RegisterObjectBehaviour("dim2f",asBEHAVE_CONSTRUCT,"void f(const dim2f &in)", asFUNCTION((Wrap::Construct1<dimension2df,dimension2df&>)),asCALL_CDECL_OBJLAST);

To this:

engine->RegisterObjectBehaviour("dim2f",asBEHAVE_CONSTRUCT,"void f(const dim2f &in)", asFUNCTION((Wrap::Construct1<dimension2df,dimension2df>)),asCALL_CDECL_OBJLAST);

Which got me another segfault, this time it looks like a whole bunch of memory got overwritten or something:

opplustroubleshooting4.png




So I switched back to a non templated wrapper function for the constructor for this issue:

static void dim2fC(const dimension2df &other, dimension2df *self)
{
new(self) dimension2df(other);
}



New registration function for it:

engine->RegisterObjectBehaviour("dim2f",asBEHAVE_CONSTRUCT,"void f(const dim2f &in)", asFUNCTION(dim2fC), asCALL_CDECL_OBJLAST);


operator+ registration code:

r = engine->RegisterObjectMethod("dim2f", "dim2f &opAdd(const dim2f &in) const", asMETHODPR(dimension2df, operator+, (const dimension2df&) const, dimension2df), asCALL_THISCALL);


And I no longer get a segfault, but in the constructor wrapper the *self pointer isn't getting the right values:

opplustroubleshooting5.png


So, upon switch the operator+ registration function back to the original:

r = engine->RegisterObjectMethod("dim2f", "dim2f opAdd(const dim2f &in) const", asMETHODPR(dimension2df, operator+, (const dimension2df&) const, dimension2df), asCALL_THISCALL);

...it made no difference, the constructor sees the exact same value for self. I am stumped at this point...I don't understand why it doesn't get the correct value...
That changing the signature to return the value by & indicates that AngelScript is thinking the dimension2df type must be returned in memory (thus passing a hidden pointer as the first argument to the function).

This tells me there is a problem with the configuration for MinGW on Windows in as_config.h.


The constructors didn't have any problem, neither the assignment operator. You've already shown that with your tests. The only problem seems to be when the method returns the type by value.


Would it be possible for you to run the test_feature project with your compiler to check which tests in the main.cpp that fail?

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game


That changing the signature to return the value by & indicates that AngelScript is thinking the dimension2df type must be returned in memory (thus passing a hidden pointer as the first argument to the function).

This tells me there is a problem with the configuration for MinGW on Windows in as_config.h.


The constructors didn't have any problem, neither the assignment operator. You've already shown that with your tests. The only problem seems to be when the method returns the type by value.


Would it be possible for you to run the test_feature project with your compiler to check which tests in the main.cpp that fail?


During the compile of the "test_feature" project, the compiler failed on the following:


E:\pb\angelscript_2.21.0\tests\test_feature\source\test_registertype.cpp||In function 'bool TestRegisterType::TestHandleType()':|
E:\pb\angelscript_2.21.0\tests\test_feature\source\test_registertype.cpp|889|error: 'asOBJ_ASHANDLE' was not declared in this scope|

This topic is closed to new replies.

Advertisement