Symbian panics when deleting dynamic array - c++

I am trying to allocate a char array of size 1000. This array
is passed to a function where it should be filled with the data
that has been received from the TCP Socket. The problem occurs
then when I try to delete[] buffer: Here I get as a result a User
Panic 42. Unfortunately, I do not really see what is going wrong
in this simple code fragement...
int main
{
unsigned char *buffer = new unsigned char[1000];
Recv(&buffer);
delete[] buffer;
return (0);
}
void Recv(unsigned char **buffer)
{
TRequestStatus iStatus;
TSockXfrLength len;
TBuf8<1000> buff;
iSocket.RecvOneOrMore( buff, 0, iStatus, len );
User::WaitForRequest(iStatus);
*buffer = ( unsigned char* )buff.Ptr();
}
Thanks for any useful hints!

What Konrad says is true, but I don't think he knows Symbian. If you do need a function to read bytes into a char buffer, then a better fix would be:
void Recv(unsigned char *aBuffer, int aSize)
{
TRequestStatus iStatus;
TSockXfrLength len;
TPtr8 buff(aBuffer, aSize);
iSocket.RecvOneOrMore( buff, 0, iStatus, len );
User::WaitForRequest(iStatus);
}
TBuf8 is a descriptor which contains an array to hold the data. TPtr8 is a descriptor which refers to an external buffer that you specify. Either can be passed into RecvOneOrMore, since they both inherit from the parameter type, TDes8&. So the socket can be made to write its data directly into your buffer, instead of writing into a buffer on the stack and then copying as Konrad's code does.
You probably also need to check the status to detect errors, and report success/failure and the length written back to the caller.

Your array allocation is without effect because inside the function, you assign a new pointer to the array:
*buffer = ( unsigned char* )buff.Ptr();
Now the buffer points to another memory location, presumably one that you may not free using delete (e.g. one on the stack, or allocated using something other than new).
To fix the problem, it's probably best to copy the data to your array:
void Recv(unsigned char *buffer)
{
TRequestStatus iStatus;
TSockXfrLength len;
TBuf8<1000> buff;
iSocket.RecvOneOrMore( buff, 0, iStatus, len );
User::WaitForRequest(iStatus);
unsigned char* const tmpbuf = static_cast<char*>(buff.Ptr());
std::copy(tmpbuf, tmpbuf + len, buffer);
}
Notice that the buffer pointer is now passed directly to the function Recv, no further indirection needed since we don't manipulate the pointer directly.

Um, you're trying to delete[] something that's not allocated by you. You're delete[]ing buff.Ptr() while leaking the array allocated in main().

Related

Casting byte array to multi-dimentional array

I have a byte array serialized from a stream char* Buf which points to an array of 64 bytes.
I wish to cast it into a function input parameter Foo(char[4][16] Buf) without copying each and every single bytes.
Any easy for doing so?
You can cast any buffer to any array you want:
void Foo(char(&buf)[4][16])
{
}
int main()
{
char* buf = new char[64];
Foo((char(&)[4][16])(buf));
delete[] buf;
return 0;
}
I found the answer in link given by Michael Chourdakis
*reinterpret_cast<char(*)[4][16]>(Buf)

pass array as parameters in function

I have a function need to pass an array and the array value will be modified in that function. I implement it as follows, but the values in the array does not change after the function is called. Could any one help me with this? Thanks!
This is where I call the function, socket.Receive(sender,buffer,sizeof(buffer)). The variable buffer does not get the right value.
while ( true )
{
Address sender;
unsigned char buffer[256];
int bytes_read = socket.Receive( sender, buffer, sizeof( buffer) );
if ( !bytes_read )
break;
printf("%d\n",buffer[92]);
}
This is the code of function socket.Receive()
int Socket::Receive( Address & sender,
void* data,
int size )
{
unsigned char packet_data[256];
unsigned int max_packet_size =
sizeof( packet_data );
#if PLATFORM == PLATFORM_WINDOWS
typedef int socklen_t;
#endif
sockaddr_in from;
socklen_t fromLength = sizeof( from );
size = recvfrom( handle,
(char*)packet_data,
max_packet_size,
0,
(sockaddr*)&from,
&fromLength );
data = packet_data;
unsigned int from_address = ntohl( from.sin_addr.s_addr );
unsigned int from_port = ntohs( from.sin_port );
return size;
}
data = packet_data;
On this line you're assigning to data but the parameter that Receive takes is a local copy of a pointer. It needs to take a reference if you are trying to mutate the argument being passed:
int Socket::Receive( Address & sender,
void*& data, // <-- reference to a pointer
int size )
And like #DrewDormann said, the assignment doesn't copy the data from packet_data to data, but rather changes the address the data points to to the address of packet_data. The consequence is that when you attempt to derefrerence buffer later on, you will get Undefined Behavior for accessing an already destroyed object.
Instead, should use memcpy to copy the data:
#include <cstring>
std::memcpy(data, packet_data, size);
You have several bugs, but the problem you mention stems from this line.
data = packet_data;
This line does not copy the entire packet_data array. It only overwrites the pointer data with a new address.
I think the problem is because you declare "unsigned char packet_data[256];" on the stack of your function and you do not copy from it the bytes to your "data" parameter. Use memcpy to copy contents of "packet_data" into "data". What you are doing instead you are assigning "data" to "packet_data", when you do that "data" will point to the same memory as "packet_data" does. But as soon as the function exits, "packet_data" is being freed, so it's contents become garbage. Hence you do not see the data in your "data" pointer. Hope this was helpful.

Can anyone give me example code of _dupenv_s?

I'm using getenv("TEMP"), but I'm getting a warning telling me to use _dupenv_s.
I can't find an example of _dupenv_s on the net.
The docs read:
errno_t _dupenv_s(
char **buffer,
size_t *numberOfElements,
const char *varname
);
But what buffer are they referring to? I only have varname. Wouldn't it be better to avoid using a buffer?
_dupenv_s is a Microsoft function, designed as a more secure form of getenv.
_dupenv_s allocates the buffer itself; you have to pass it a pointer to a pointer and it sets this to the address of the newly allocated buffer.
For example,
char* buf = nullptr;
size_t sz = 0;
if (_dupenv_s(&buf, &sz, "EnvVarName") == 0 && buf != nullptr)
{
printf("EnvVarName = %s\n", buf);
free(buf);
}
Note that you're responsible for freeing the returned buffer.

Convert a string to and unsigned char []

I currently have a Packet set up like so:
struct Packet {
unsigned short sequenceNumber;
unsigned short length;
unsigned char control;
unsigned char ack;
unsigned short crc;
unsigned char data[];
Packet copy(const Packet& aPacket) {
sequenceNumber = aPacket.sequenceNumber;
length = aPacket.length;
control= aPacket.control;
ack = aPacket.ack;
crc = aPacket.crc;
memcpy (data, aPacket.data, aPacket.length);
}
};
This packet gets converted into a string for encryption and then needs to be taken from its decrypted string form back to a Packet. I am able to do this fine for all of the variables except for the unsigned char data[]. I have tried the following with no success:
string data = thePack.substr(pos, thePack.length()-pos);
unsigned char * cData = new unsigned char[data.length()];
strcpy((char *)cData, data.c_str());
memcpy(p.data, cData, data.length());
where data is the string representation of the data to be copied into the unsigned char [] and p is the Packet.
This gives the following from valgrind:
==16851== Invalid write of size 1
==16851== at 0x4A082E7: strcpy (mc_replace_strmem.c:303)
Even though it cites strcpy as the source, it compiles and runs fine with just the memcpy line commented out.
I have also tried replacing memcpy with strcpy with the same result. Any ideas? I feel that it might be due to the fact that data may have not been initialized and there for not have any memory allocated to it, but I thought memcpy would take care of this.
You haven't specified the size of the data array.
unsigned char data[];
This is legal, but rather difficult to use. The data array will follow the rest of the Packet structure in memory, but the compiler doesn't know how much space to allocate for it. So you have to allocate the extra space yourself:
size_t datalen = thePack.length()-pos;
void* pbuffer = malloc( sizeof (Packet) + datalen + 1 );
Packet* p = new (pbuffer) Packet;
memcpy(p.data, &thePack[pos], datalen);
p.data[datelen] = 0;
What won't work is letting the compiler decide how big a Packet should be, either using new Packet or a local variable Packet p;. That will end up with no space reserved for data. And no, memcpy doesn't allocate memory.
A much cleaner solution would be to use a std::vector for your variable-sized data array.
The char[] you're allocating is one character too small -- you must leave room for the NULL byte at the end:
unsigned char * cData = new unsigned char[data.length() + 1];
Use the strcpy version to copy the string, so the NULL byte gets copied correctly. Although it might run OK without that +1, there's no guarantee, and sometimes it might crash.

C++ using strcpy_s() on a Pointer to char array Pointer

I am to the point I am confusing myself but here is what I have. I have only recently started to familiarize myself with pointers more to a point I feel more comfortable using them, but I am getting an error about the buffer in strcpy_s() being too small.
Please no comments about me using char arrays instead of std::string, its for the HL2SDK which centers around char arrays (no idea why) so I just stick to the pattern.
void func_a()
{
char *szUserID = new char[64];
char *szInviterID = new char[64];
char *szGroupID = new char[64];
sprintf(szUserID, "%I64d", GetCommunityID(szUserSteamID));
sprintf(szInviterID, "%I64d", GetCommunityID(g_CvarSteamID.GetString()));
GetGroupCommunityID(1254745, &szGroupID); // Group Steam Community ID
}
void GetGroupCommunityID(int groupID, char **communityID)
{
int staticID = 1035827914;
int newGroupID = 29521408 + groupID;
char *buffer = new char[64];
snprintf(buffer, sizeof(buffer), "%d%d", staticID, newGroupID);
strcpy_s(*communityID, sizeof(*communityID), buffer);
delete buffer;
}
The problem is you are using sizeof which is a compile time construct to determine the runtime length of *communityID. This will essentially resolve down to sizeof(char*). What you want though is the number of bytes / chars available in *communityID. This information needs to be passed along with the value
GetGroupCommunityID(1254745, &szGroupID, sizeof(szGroupID));
void GetGroupCommunityID(int groupId, char** communityID, size_t length) {
...
strcpy_s(*communityID, length, buffer);
}
Also in this example a double pointer is unnecessary because you're not changing the pointer, just it's contents. A single pointer will do just fine for that
GetGroupCommunityID(1254745, szGroupID, sizeof(szGroupID));
void GetGroupCommunityID(int groupId, char* communityID, size_t length) {
...
strcpy_s(communityID, length, buffer);
}
If you are using constants values (char *szGroupID = new char[64]) why not declare a constant with the value 64 and use this value; by the way sizeof(szGroupID) is going to return 4 bytes too in a 32 bits compiler.
The second parameter to strcpy_s is the actual size (number of characters) of the buffer pointed to by the first parameter. sizeof(*communityID) only gives you the size of a char * pointer, typically 4 bytes on a 32-bit system. You need to pass in the actual size of *communityID to the GetGroupCommunityID function and pass this on to strcpy_s.