Download MetaTrader 5

Returning a char* string from a DLL in MT4 eats memory - page 2

To add comments, please log in or register
Publish your article and get a reward!
ziggy
57
ziggy 2010.04.12 20:35  
Yes, your are totally right. It was just some fast copy/paste from me. This is more like I have done it. It could be more ways to do this but this is how I ended up, and it works.

void FunctionWithoutMemoryLeak(MqlStr* fieldValue)
{
char *value = GetValueFromSomeFunction();

strcpy(fieldValue[0].string, value);
fieldValue[0].len = strlen(value);

delete [] value;
}
Brian
9
Brian 2010.04.16 13:23  

I did some investigation into this, and it seems you need to tread very carefully when dealing with passed strings. The code sample above is unsafe and could cause a crash.

The first part of the problem comes in the MqlStr struct reference - it seems that while MQL4 reserves 4 bytes for the string size, it doesn't populate the length field (my code showed 0 for the size) so you can't use that to determine the size of the buffer. As such, you will need to pre-define a contract on the string size (some max size would be a safe bet).

The second part is the code above can easily cause a buffer overrun. While you are properly allocating the buffer size of the source string (new char[5]), the destination buffer you are copying into (fieldValue[0].string) is an unknown size. If it is less than 5 bytes, then you are causing a buffer overrun.

Here's an example: C++ snippet

strcpy(fieldValue[0].string, "1234Buffer Overrun"); // fieldValue is a struct MqlStr
MQL4 snippet:
string fieldValue[2] = { "Hi", "Happy Days Are Here" };
ExternalFunction(fieldValue); // This executes the C++ code above
string fixString = fieldValue[1];
MessageBox(fixString);
What happened here is the strcpy overran the buffer of fieldValue[0] and right on top of fieldValue[1]. In fact, the text in MessageBox will be "Buffer Overrun".

With that said, there is a way around this, but I strongly recommend against it for anything besides proof-of-concept code. C++ snippet:
fieldValue[0].string = "Hack";
Basically, this is replacing the pointer that MQL4 is using for the string. However, you have now leaked the old fieldValue[0].string, and you don't know which cleanup method MQL4 might attempt to use on your string (which itself could cause a crash). If one of the MQL4 programmers told us some of the inner workings regarding strings, this could be made safe.

Brian
ziggy
57
ziggy 2010.04.20 13:37  
TraderBrian:

I did some investigation into this, and it seems you need to tread very carefully when dealing with passed strings. The code sample above is unsafe and could cause a crash.

The first part of the problem comes in the MqlStr struct reference - it seems that while MQL4 reserves 4 bytes for the string size, it doesn't populate the length field (my code showed 0 for the size) so you can't use that to determine the size of the buffer. As such, you will need to pre-define a contract on the string size (some max size would be a safe bet).

The second part is the code above can easily cause a buffer overrun. While you are properly allocating the buffer size of the source string (new char[5]), the destination buffer you are copying into (fieldValue[0].string) is an unknown size. If it is less than 5 bytes, then you are causing a buffer overrun.

Here's an example: C++ snippet

strcpy(fieldValue[0].string, "1234Buffer Overrun"); // fieldValue is a struct MqlStr
MQL4 snippet:
string fieldValue[2] = { "Hi", "Happy Days Are Here" };
ExternalFunction(fieldValue); // This executes the C++ code above
string fixString = fieldValue[1];
MessageBox(fixString);
What happened here is the strcpy overran the buffer of fieldValue[0] and right on top of fieldValue[1]. In fact, the text in MessageBox will be "Buffer Overrun".

With that said, there is a way around this, but I strongly recommend against it for anything besides proof-of-concept code. C++ snippet:
fieldValue[0].string = "Hack";
Basically, this is replacing the pointer that MQL4 is using for the string. However, you have now leaked the old fieldValue[0].string, and you don't know which cleanup method MQL4 might attempt to use on your string (which itself could cause a crash). If one of the MQL4 programmers told us some of the inner workings regarding strings, this could be made safe.

Brian

Yep, what I have done is to pass a predefined string of 255 characters to the function. That is the maximum MQL can handle. I have not experienced any buffer overruns when doing that, but it is not a very elegant solution. But as long as it works and I have no memory leak I am happy with it until I can find a better solution.
And yes the length field seems to do nothing to me too, but it does not seem to do any harm to set it to the length of the string either. If you replace the pointer to the string you will have a memory leak and the memory usage of terminal.exe will grow into the sky. To me it seems that MQL have no way of handling that at all.

raidsan
89
raidsan 2010.05.17 09:08  

#import "mytest.dll"

void getstr(string retstr)

#import


void getstr(char * retstr)

{

char *value = new char[4];

strcpy(value, "Test");

strcpy(retstr, value);

delete [] value;

}


It would work, don't know why. if define : "void getstr(string& retstr)", it will cause crash.

but before call getstr(string) in mq4, input string must be init, e.g.


string var1 = "";

getstr(var1); //shoud ok

string var2;

getstr(var2); //may cause mt4 crash

raidsan
89
raidsan 2010.05.17 09:56  
TraderBrian:


Here's an example: C++ snippet

strcpy(fieldValue[0].string, "1234Buffer Overrun"); // fieldValue is a struct MqlStr
MQL4 snippet:
string fieldValue[2] = { "Hi", "Happy Days Are Here" };
ExternalFunction(fieldValue); // This executes the C++ code above
string fixString = fieldValue[1];
MessageBox(fixString);
What happened here is the strcpy overran the buffer of fieldValue[0] and right on top of fieldValue[1]. In fact, the text in MessageBox will be "Buffer Overrun".

It would not overrun the buffer. The important thing is, fieldValue[0], fieldValue[1]..., must be init use a value, even use "", after that it will init a string point.
Jitendra Parmar
1093
Jitendra Parmar 2013.07.14 21:57  
does anybody ever tried this solution in C# dll ,  I have tried every thing MqlStr  ,  char * c  = new char [] , dont allow , waiting for you expert suggestion
Simon Gniadkowski
Moderator
18001
Simon Gniadkowski 2013.07.15 07:26  
hijeenu:
does anybody ever tried this solution in C# dll ,  I have tried every thing MqlStr  ,  char * c  = new char [] , dont allow , waiting for you expert suggestion
Please do not double post . . .  especially to old threads.
thachvan
12
thachvan 2017.03.18 09:05  

I don't know why you guys make it to be very complicated here. The solution is very simple.

* C++:

#define MT4EXPORT extern "C" __declspec(dllexport)

MT4EXPORT void getText(char* buffer)

{

char* text = "ABCD";

strcpy(buffer, text);

}

* MQL:

#import "MT4 DLL.dll"

void getText(char&[]);

#import


int OnInit()

{

char buffer[1024];

getText(buffer);

string text=CharArrayToString(buffer);

Print(text); // ABCD


return(INIT_SUCCEEDED);

}
Ex Ovo Omnia
3155
Ex Ovo Omnia 2017.03.18 11:07  
thachvan:

I don't know why you guys make it to be very complicated here. The solution is very simple.

* C++:

* MQL:


I am afraid you missed ziggy by more than 6 years with your reply.
ziggy
ziggy
  • www.mql5.com
Trader's profile
whroeder1
14527
whroeder1 2017.03.18 13:19  
string text=CharArrayToString(buffer);
Six year old thread, and provides a solution that didn't exist until February 3, 2014 (Build 600)
12
To add comments, please log in or register