I been working in a project that handles some char* pointers, and it's a requisite of the class to use char* instead of std::string, so...
I have this structure definition and this queue:
typedef struct packetQueue
{
char* buf;
int length;
packetQueue()
{
buf = new char[];
length = 0;
}
} PACKET;
concurrency::concurrent_queue IP_in_queue;
I have this buffer:
char sendBuf[MSG_SIZE + sizeof (IP_PACKET_HEADER_T) + 1]; // String to be send
and a structure for my new buffer:
PACKET ipQueue;
then I fill my buffer with this:
// Concatenates the header with sended message
memcpy(sendBuf, (void*)&sendHeader, sizeof(sendHeader));
memcpy(&sendBuf[sizeof(sendHeader)], readMessage, sendHeader.length);
ipQueue.buf = sendBuf;
ipQueue.length = packetSize;
And then I push my packet to my queue
IP_in_queue.push(ipQueue); // Push the buffer in the IP_in_queue
This is my loop just in case:
while ( 1 )
{
// Get the user input
cout << "> ";
cin.getline (buf, BUFLEN);
IP_PACKET_HEADER_T sendHeader; // Store the header to be send
PACKET ipQueue;
char* fakeIPAddressDst, *readMessage;
delay = atoi(strtok (buf," ")); // Takes the first delay value
fakeIPAddressDst = strtok (NULL, " "); // Stores the IP Address
readMessage = strtok (NULL, " "); // Stores the sended message
Sleep(delay); // Sleep the miliseconds defined
// Fills the header with the data neccesary data
sendHeader.DIP = inet_addr(fakeIPAddressDst);
sendHeader.SIP = inet_addr(initAddress.fakeIpAddress);
sendHeader.length = getStringLength(readMessage) + 1;
packetSize = sizeof( sendHeader ) + sendHeader.length; // Defines the size of the packet to be send
// Concatenates the header with sended message
memcpy(sendBuf, (void*)&sendHeader, sizeof(sendHeader));
memcpy(&sendBuf[sizeof(sendHeader)], readMessage, sendHeader.length);
ipQueue.buf = sendBuf;
ipQueue.length = packetSize;
numbytes = packetSize; // The number of bytes of sended buffer
char sendedString[BUFLEN + 1]; // Variable for stores the data
IP_PACKET_HEADER_T readHeader; // To store the header for showing the information
// Print out the content of the packet
// Copy from buf to the header
memcpy( (void*)&readHeader, ipQueue.buf, sizeof( IP_PACKET_HEADER_T));
// Copy message part
memcpy( sendedString, &ipQueue.buf[sizeof(IP_PACKET_HEADER_T)], numbytes - sizeof(IP_PACKET_HEADER_T));
// Append \0 to the end
sendedString[numbytes - sizeof(IP_PACKET_HEADER_T)] = '\0';
// Save the IP information of the packet in a struct for print on the screen
struct in_addr fakeAddrHost;
fakeAddrHost.s_addr = readHeader.SIP;
// Print the neccesary data
cout << "[IN] DST: " << fakeIPAddressDst << endl; // Fake IP address of the destination
cout << "[IN] SRC: " << inet_ntoa(fakeAddrHost) << endl; // Fake IP address of the host
cout << "[IN] MSG: " << sendedString << endl ; // Message to send
IP_in_queue.push(ipQueue); // Push the buffer in the IP_in_queue
}
I know there is a memory leak in this procedure but I'm not sure.
When I push my packet, the buf pointer keeps pointing to my sendBuf, am I right? Because the assignment does that, but if I delete my pointer in the ipQueue after I push the program crashes. I have to say, after I push that struct into the queue, another thread try to pop that one, and obviously if I delete my ipQueue pointer I'll lost my buffer, so how can I avoid this memory leak?
Thanks
EDIT:
The memory leak using the definition of buf = nullptr
---------- Block 1 at 0x0068BB30: 264 bytes ----------
Call Stack:
d:\program files (x86)\microsoft visual studio 11.0\vc\include\concurrent_queue.h (402): Host.exe!Concurrency::concurrent_queue<packetQueue,std::allocator<packetQueue> >::_Allocate_page + 0xF bytes
f:\dd\vctools\crt_bld\self_x86\crt\src\concurrent_queue.cpp (113): MSVCP110D.dll!Concurrency::details::_Micro_queue::_Push + 0xD bytes
f:\dd\vctools\crt_bld\self_x86\crt\src\concurrent_queue.cpp (232): MSVCP110D.dll!Concurrency::details::_Concurrent_queue_base_v4::_Internal_push
d:\program files (x86)\microsoft visual studio 11.0\vc\include\concurrent_queue.h (566): Host.exe!Concurrency::concurrent_queue<packetQueue,std::allocator<packetQueue> >::push + 0xF bytes
d:\users\silex rpr\documents\visual studio 2012\projects\project2\project2\host.cpp (802): Host.exe!main
f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c (536): Host.exe!__tmainCRTStartup + 0x19 bytes
f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c (377): Host.exe!mainCRTStartup
0x7662339A (File and line number not available): kernel32.dll!BaseThreadInitThunk + 0x12 bytes
0x77179EF2 (File and line number not available): ntdll.dll!RtlInitializeExceptionChain + 0x63 bytes
0x77179EC5 (File and line number not available): ntdll.dll!RtlInitializeExceptionChain + 0x36 bytes
First off; this isn't C, you're using a C++ compiler. structures in C cannot have methods and constructors and new and delete don't exist.
Secondly, you allocate memory for buf in your constructor, but then...
ipQueue.buf = sendBuf;
That's a leak. You need to call delete for every call to new. You allocate buf with new, but never call delete on it, so that memory is leaked.
I see no reason to allocate buf here. Just set it to null.
typedef struct packetQueue
{
char* buf;
int length;
packetQueue()
: buf(nullptr), length(0) { }
} PACKET;
On a side note, this is a very nasty mix of C and C++. Is this what your teacher is teaching you guys?
You've got a class (structure) with a constructor that allocates memory and no destructor that releases it, so you get memory leaks.
You also expose the buf member and assign to it; so your class has no control over whether the memory should be freed or not. But you need to free the memory allocated in the constructor before you assign to the buf the first time.
To get this right, you'll need to make the buf field private and add a destructor, a copy constructor and an assignment operator (and probably an accessor function). You'll still not be exception safe, though.
The problem you have is that you haven't looked at copy construction and copy assignment: when you push an object into a std::vector<T> it gets copied and the objects with the std::vector<T> get possibly moved around using assignment. The default generated copy constructor and copy assignment just copy or assign the respective members, i.e., whenever either copy is used, you'd end up with two objects pointing to the same buf. The first one destroyed would use delete[] buf; and all others would have a stale pointer which can't be deleted again. That is, you want to add three methods to your packetQueue:
struct packetQueue
{
packetQueue(packetQueue const& other); // copy constructor: copies the content
packetQueue& operator= (packetQueue const& other); //copy assignment: updates the content
~packetQueue() // destructor: release the memory
void swap(packetQueue& other); // swap the content
// other members
};
To leverage the copy construction and destruction in the copy assignment, I find it useful to have a swap() member, because this is easily implemented and makes for a nice, simple copy assignment:
void packetQueue::swap(packetQueue& other) {
std::swap(this->buf, other.buf);
std::Swap(this->size, other.size);
}
packetQueue& packetQueue::operator= (packetQueue const& other) {
packetQueue(other).swap(*this);
return *this;
}
Related
I am using a tcp server that I wrote for handling inputs into a database. I have a tcp client sitting on a server that sends the filename to a tcp server sitting on a different linux server. once the filename is received the linux server goes into a shared folder and pulls the file then inserts it into the database.
my problem is with correctly declaring the buffer and clearing it to make sure I get the correct filename without any gibberish added or anything removed from it.
right now it is working like this:
char data[1024];
which is fine but it does not automatically delete the buffer completely, so i tried to implicitly allocate memory to "data" such as:
char *data = (char*) malloc(1024 * sizeof(char));
...
free(data);
OR
char *data = new char[1024];
...
delete[] data;
For some reason the above two declaration are declaring a buffer of size =8 I got this using
sizeof(data);
also what I am receiving is only 8 characters long. I am not sure why it is doing this, any help??
EDIT
char *data = (char*)malloc(1048 * sizeof(char));
if(data==NULL) exit(1);
cout << "DATA Size: " << sizeof(data) << "\n";
int msglen = read(conn, data, sizeof(data));
cout << "Server got " << msglen << " byte message: " << data << "\n";
if(write(conn, &msglen, sizeof(msglen))<0){
cout << "Failed to write back to the client " << strerror(errno);
}
free(data);
close(conn);
There are several things wrong with your code.
1) dont use malloc - you flagged your question as c++ - use malloc only when necessary replace it with:
const int dataSize = 1024;
char *data = new char[dataSize];
2) sizeof(data) when data is char* returns 8 because it returns size of a pointer not an array when you declare data as array sizeof will return bytes occupied by whole array. you should replace you read with:
int msglen = read(conn,data,dataSize)
3) I assume that u want to write data u've just received back to sender.. Then:
in write function you put sizeof(msglen) as third argument which will (mostly) always return 4. remove sizeof( ).
write(conn, data, msglen);
after you are done with the data dont forget to clear the memory using:
delete[] data;
use delete[] always when you assigned memory with new[].
API write(int socket, char *buf, int len);
Code becomes this:
write(con, data, msglen);
Assuming you can't use the stack (e.g. char buf[1024]), using naked pointers is discouraged as bad style and bug prone. Instead, use RAII and some variant of amanged memory, such as shared_ptr or unique_ptr.
#include <memory> and use a std::shared_ptr<>, or std::unique_ptr<> plus std::move() to return the buffer:
std::size_t bufSize = 1024;
std::unique_ptr<char[]> myUniqueBuf(new char[bufSize]);
ssize_t msglen = ::read(conn, *myUniqueBuf, bufSize); // return type is ssize_t, not int
return std::move(myUniqueBuf); // If you need to return the buffer
// I think you will probably prefer a shared_ptr<> because it has a copy
// constructor which makes it easier to pass around and return from functions
std::shared_ptr<char[]> mySharedBuf(new char[1024]);
ssize_t msglen = ::read(conn, *mySharedBuf, bufSize); // return type is ssize_t, not int
ssize_t bytesOut = ::write(conn, *mySharedBuf, msglen);
return mySharedBuf;
The advantage to std::shared_ptr or std::unique_ptr is that you don't have to worry about cleaning up a naked pointer (i.e. calling delete[] data;) because with managed memory it will happen automatically for you when the buffer handle goes out of scope or the reference count goes to zero (e.g. myUniqueBuf or mySharedBuf).
I have this program that reads data from a serial port. For each line, I'm trying to concatenate the current time with the line of data. For some reason, it crashes when around the second print (it seems like at the end of the brackets?). The weird part is, that if I comment the print out, it'll still crash
char * cdata;
{
if( BINARY_ASCII == 1 ) //right now this is just set to 0, please ignore
{
cdata = convertBSTRToByteArray(data , numChars);
}
else
{
cdata = convertBSTRToString(data);
//prints the original output
cout << "before timestamp concat is: " << cdata << "\n";
//this is supposed to concatenate each output line with the associated time
std::stringstream ss;
ss << currentDateTime() << "," << cdata;
std::string s = ss.str();
std::strcpy(cdata,s.c_str());
cout << "after timestamp concat is: " << cdata << "\n"; //around here it crashes
}
cout << "after the thing" << "\n"; //does not even get here
I thought that the char * data would be the issue, but I've tried initializing it like
char *cdata = 0;
and
char *cdata = new char [100];
to no change...
That makes me think that I did something wrong in the concatenation?
I think it's important to highlight the difference between arrays and pointers, here.
char * cdata;
This creates a pointer named cdata. It's uninitialized, so it contains some useless memory address. A pointer is just a memory address, which means it takes up 32 (or 64) bits, and that's it.
char *cdata = 0;
This creates a pointer named cdata, and initializes it to all zeros, which means it points to the 0th location in memory. This is usually used to indicate that you should not follow this pointer.
char *cdata = new char [100];
This creates a block (array) of 100 characters, but gives that array no name. Then it creates a pointer named cdata and sets it to the memory address of the unnamed 100-byte block. I.e.:
cdata [ 0x3Ad783B2 ] --------\
\
\
|
V
[ unnamed 100-byte block ]
The reason I'm stressing this distinction is that the next line obliterates it all:
cdata = convertBSTRToString(data);
That line sets cdata to point to whatever memory address is returned by convertBSTRToString. It does not matter what value cdata had before this line -- uninitialized, null, pointing to an unnamed block of memory -- now it is pointing to the block of memory created by convertBSTRToString.
Abusing more ASCII-art:
cdata [ 0x64ADB7C8 ] --------\
\
\
|
V
[ unknown size, created by convertBSTRToString ]
// hey, look over here! it still exists,
// but we just don't point to it anymore.
[ unnamed 100-byte block ]
Now that that's covered, here's why it matters. This line:
std::strcpy(cdata,s.c_str());
strcpy will take the data pointed to by the second parameter, and copy it, byte-by-byte, to the location pointed to by the first parameter. It does not pay attention to buffer size. It's a really stupid copy. No safety whatsoever - that's up to you to provide.
I'm not sure what you're trying to accomplish with this line anyway, because s holds the full string data you wanted to concatenate:
cout << "after timestamp concat is: " << s << "\n";
convertBSTRToString probably allocates a new buffer that's sized exactly right to hold the BSTR you passed in. That means you cannot expand its size.
In your code, you are trying to add currentDateTime()'s result into that buffer (in addition to its existing content). The data won't fit. Thus, bad things happen.
You would need to first allocate a buffer big enough to contain both the convertBSTRToString plus the currentDateTime then strcpy the convertBSTRToString and then strcat the currentDateTime. strcpy won't append, strcat does.
None of the posted answers I've read work, so I'm asking again.
I'm trying to copy the string data pointed to by a char pointer into a char array.
I have a function that reads from a ifstream into a char array
char* FileReader::getNextBytes(int numberOfBytes) {
char *buf = new char[numberOfBytes];
file.read(buf, numberOfBytes);
return buf;
}
I then have a struct :
struct Packet {
char data[MAX_DATA_SIZE]; // can hold file name or data
} packet;
I want to copy what is returned from getNextBytes(MAX_DATA_SIZE) into packet.data;
EDIT: Let me show you what I'm getting with all the answers gotten below (memcpy, strcpy, passing as parameter). I'm thinking the error comes from somewhere else. I'm reading a file as binary (it's a png). I'll loop while the fstream is good() and read from the fstream into the buf (which might be the data array). I want to see the length of what I've read :
cout << strlen(packet.data) << endl;
This returns different sizes every time:
8
529
60
46
358
66
156
After that, apparently there are no bytes left to read although the file is 13K + bytes long.
This can be done using standard library function memcpy, which is declared in / :
strcpy(packet.data, buf);
This requires file.read returns proper char series that ends with '\0'. You might also want to ensure numberOfBytes is big enough to accommodate the whole string. Otherwise you could possibly get segmentation fault.
//if buf not properly null terminated added a null char at the end
buf[numberofbytes] = "\0"
//copy the string from buf to struc
strcpy(packet.data, buf);
//or
strncpy(packet.data, buf);
Edit:
Whether or not this is being handled as a string is a very important distinction. In your question, you referred to it as a "string", which is what got us all confused.
Without any library assistance:
char result = reader.getNextBytes(MAX_DATA_SIZE);
for (int i = 0; i < MAX_DATA_SIZE; ++MAX_DATA_SIZE) {
packet.data[i] = result[i];
}
delete [] result;
Using #include <cstring>:
memcpy(packet.data, result, MAX_DATA_SIZE);
Or for extra credit, rewrite getNextBytes so it has an output parameter:
char* FileReader::getNextBytes(int numberOfBytes, char* buf) {
file.read(buf, numberOfBytes);
return buf;
}
Then it's just:
reader.getNextBytes(MAX_DATA_SIZE, packet.data);
Edit 2:
To get the length of a file:
file.seekg (0, ios::end);
int length = file.tellg();
file.seekg (0, ios::beg);
And with that in hand...
char* buffer = new char[length];
file.read(buffer, length);
Now you have the entire file in buffer.
strlen is not a valid way to determine the amount of binary data. strlen just reads until it finds '\0', nothing more. If you want to read a chunk of binary data, just use a std::vector, resize it to the amount of bytes you read from the file, and return it as value. Problem solved.
I'm trying to split up data into little packets. I'm not exactly sure how this read method is suppose to work but I've given a buffer size of 512 to read from the file.
But instead of getting 512 i just get 5 in my first packet. Others vary from 0 to above 512 ( which shouldn't happen).
It's a zip file I'm trying to split up:
In text the first few bytes look like this
(de bucket like characters are actually 2 characters)
It seems to grab the first 5 bytes as it should but afterwards just stops and goes to the next read block.
Since it's a buffer of 512 everything after the first 5 bytes is garbage.
I'm using an ifstream. And the mode is set to Binary.
Any suggestions?
void FileProcessor::send()
{
//If no file is opened return
if(!_file.is_open()) return;
//Reset position to beginning
_file.seekg(0, ios::beg);
//Result buffer
char * buffer;
char * partBytes = new char[_bufferSize];
//Read the file and send it over the network
while (_file.read(partBytes, _bufferSize))
{
buffer = Packet::create(Packet::FILE,partBytes);
Packet *p = Packet::create(buffer);
//cout << strlen(partBytes);
//p->PrintHex(buffer,_bufferSize+Packet::HeaderSize);
//break;
cout << "Normal size : \t" << strlen(partBytes)<< "\tPacketSize: \t" << p->getLength()<<"\n";
//cout << strcmp(p->getData().c_str(),partBytes) << "\n";
writeToFile(p->getData().c_str(),p->getData().length());
delete p;
}
//Write final bytes if any
if(_file.gcount())
{
//writeToFile(partBytes, _file.gcount());
buffer = Packet::create(Packet::FILE,partBytes);
Packet *p = Packet::create(buffer);
writeToFile(p->getData().c_str(),p->getData().length());
//cout << p->getLength() << "\n";
delete p;
}
//cout<< *p << "\n";
delete [] partBytes;
}
Im just testing a direct read write right now.
Inside your loop, instead of assuming it always reads a full buffer of data, use gcount() to find how many it actually read, and transmit that many.
I feel obliged to add that this:
buffer = Packet::create(Packet::FILE,partBytes);
Packet *p = Packet::create(buffer);
looks quite strange to me. Not sure it's wrong, but it's not immediately obvious that it's right either (and if it is right, the design seems a bit odd).
I'd also skip the dynamic allocation and deletion:
char * partBytes = new char[_bufferSize];
// ...
delete [] partBytes;
and use a std::vector<char> instead.
I'm currently working on a small C++ project where I use a client-server model someone else built. Data gets sent over the network and in my opinion it's in the wrong order. However, that's not something I can change.
Example data stream (simplified):
0x20 0x00 (C++: short with value 32)
0x10 0x35 (C++: short with value 13584)
0x61 0x62 0x63 0x00 (char*: abc)
0x01 (bool: true)
0x00 (bool: false)
I can represent this specific stream as :
struct test {
short sh1;
short sh2;
char abc[4];
bool bool1;
bool bool2;
}
And I can typecast it with test *t = (test*)stream; However, the char* has a variable length. It is, however, always null terminated.
I understand that there's no way of actually casting the stream to a struct, but I was wondering whether there would be a better way than struct test() { test(char* data) { ... }} (convert it via the constructor)
This is called Marshalling or serialization.
What you must do is read the stream one byte at a time (or put all in a buffer and read from that), and as soon as you have enough data for a member in the structure you fill it in.
When it comes to the string, you simply read until you hit the terminating zero, and then allocate memory and copy the string to that buffer and assign it to a pointer in the struct.
Reading strings this way is simplest and most effective if you have of the message in a buffer already, because then you don't need a temporary buffer for the string.
Remember though, that with this scheme you have to manually free the memory containing the string when you are done with the structure.
Just add a member function that takes in the character buffer(function input parameter char *) and populates the test structure by parsing it.
This makes it more clear and readable as well.
If you provide a implicit conversion constructor then you create a menace which will do the conversion when you least expect it.
When reading variable length data from a sequence of bytes,
you shouldn't fit everything into a single structure or variable.
Pointers are also used to store this variable length.
The following suggestion, is not tested:
// data is stored in memory,
// in a different way,
// NOT as sequence of bytes,
// as provided
struct data {
short sh1;
short sh2;
int abclength;
// a pointer, maybe variable in memory !!!
char* abc;
bool bool1;
bool bool2;
};
// reads a single byte
bool readByte(byte* MyByteBuffer)
{
// your reading code goes here,
// character by character, from stream,
// file, pipe, whatever.
// The result should be true if not error,
// false if cannot rea anymore
}
// used for reading several variables,
// with different sizes in bytes
int readBuffer(byte* Buffer, int BufferSize)
{
int RealCount = 0;
byte* p = Buffer;
while (readByte(p) && RealCount <= BufferSize)
{
RealCount++
p++;
}
return RealCount;
}
void read()
{
// real data here:
data Mydata;
byte MyByte = 0;
// long enough, used to read temporally, the variable string
char temp[64000];
// fill buffer for string with null values
memset(temp, '\0', 64000);
int RealCount = 0;
// try read "sh1" field
RealCount = (readBuffer(&(MyData.sh1), sizeof(short)));
if (RealCount == sizeof(short))
{
// try read "sh2" field
RealCount = readBuffer(&(MyData.sh2), sizeof(short));
if (RealCount == sizeof(short))
{
RealCount = readBuffer(temp, 64000);
if (RealCount > 0)
{
// store real bytes count
MyData.abclength = RealCount;
// allocate dynamic memory block for variable length data
MyData.abc = malloc(RealCount);
// copy data from temporal buffer into data structure plus pointer
// arrays in "plain c" or "c++" doesn't require the "&" operator for address:
memcpy(MyData.abc, temp, RealCount);
// comented should be read as:
//memcpy(&MyData.abc, &temp, RealCount);
// continue with rest of data
RealCount = readBuffer(&(MyData.bool1), sizeof(bool));
if (RealCount > 0)
{
// continue with rest of data
RealCount = readBuffer(&(MyData.bool2), sizeof(bool));
}
}
}
}
} // void read()
Cheers.