In short, firstly I binded a global memory pool to the engine, then I assigned a class that also uses the same memory pool as string class. When I try to run some short code, the engine attempts to release memory (an instance of binded string class) inside an large allocated memory (it seems like the stack of the run-time). Is that a designed behavior so that my memory pool shall allow freeing part of its allocated memory, or it is an error caused by my incorrect binding?
The script code that was run with error is:
const char* code =
"void main() {\n"
" Identifier a = \"abc\";\n"
"}";
Specifically, if I run script code without assignment operator, it won't crash:
const char* code =
"void main() {\n"
" \"abc\";\n"
"}";
More details:
I'm using JUCE Identifier as string class for the AngelScript engine. It is registered as a value type.
I used GENERIC function binding at all places for maximum compatibility.
The code below are Identifier methods. Specifically, the assignment operator is registered with void opAssign(Identifier)
signature.
static void Identifier_construct( asIScriptGeneric* ctx )
{
void* mem = ctx->GetObject();
new ( mem ) juce::Identifier;
}
static void Identifier_destruct( asIScriptGeneric* ctx )
{
void* mem = ctx->GetObject();
( (juce::Identifier*) mem )->~Identifier();
}
static void Identifier_eq( asIScriptGeneric* as )
{
auto* a = reinterpret_cast< juce::Identifier* >( as->GetObject() );
auto* b = reinterpret_cast< juce::Identifier* >( as->GetArgObject( 0 ) );
as->SetReturnByte( *a == *b );
}
static void Identifier_assign( asIScriptGeneric* as )
{
auto* self = reinterpret_cast< juce::Identifier* >( as->GetObject() );
auto* peer = reinterpret_cast< juce::Identifier* >( as->GetArgObject(0) );
*self = *peer;
}
And the code below is the string factory:
struct IdentifierStringFactory : public asIStringFactory
{
static IdentifierStringFactory& getInstance()
{
static IdentifierStringFactory obj;
return obj;
}
const void* GetStringConstant( const char* data, asUINT len ) override;
int ReleaseStringConstant( const void* str ) override;
int GetRawStringData( const void* str, char* data, asUINT* len ) const override;
};
const void* IdentifierStringFactory::GetStringConstant( const char* data, asUINT len )
{
void* mem = threadedPooledAlloc( sizeof( juce::Identifier ) );
return new ( mem ) juce::Identifier( data );
}
int IdentifierStringFactory::ReleaseStringConstant( const void* str )
{
juce::Identifier* id = (juce::Identifier*) str;
id->~Identifier();
threadedPooledFree( id );
return 0;
}
int IdentifierStringFactory::GetRawStringData( const void* str, char* data, asUINT* len ) const
{
juce::Identifier* id = (juce::Identifier*) str;
auto sz = id->getCharPointer().sizeInBytes();
if ( data == nullptr )
*len = asUINT( sz );
else
memcpy( data, id->getCharPointer().getAddress(), sz );
return 0;
}