I'm getting a memory leak from the following function:
int ReadWrite(int socket, char *readfile) {
FILE *rf = NULL;
rf = fopen(readfile, "rb");
fseek(rf, 0, SEEK_END);
int len = ftell(rf);
rewind(rf);
char readbuf[len + 1];
int res = fread(readbuf, len, 1, rf);
readbuf[len + 1] = '\0';
fclose(rf);
while (1) {
int wres = write(socket, readbuf, res);
if (wres == 0) {
cerr << "socket closed prematurely" << endl;
close(socket);
return EXIT_FAILURE;
}
if (res == -1) {
if (errno == EINTR)
continue;
cerr << "socket write failure: " << strerror(errno) << endl;
close(socket);
return EXIT_FAILURE;
}
break;
}
return EXIT_SUCCESS;
}
Valgrind tells me I leak the number of bytes that are in readfile (the actual file, not the name of readfile) through this operation:
Address 0x4c3b67e is 0 bytes after a block of size 14 alloc'd
at 0x4A07C84: operator new[](unsigned long) (vg_replace_malloc.c:363)
What's confusing me is I don't ever use new[] in my code. I checked fopen, ftell, and fread to see if they have hidden "gotcha's" where they call new[] somewhere but didn't find anything in the documentation on cplusplus.com. I've tried all different combinations of new char[]/delete[], malloc/free, and stack-allocated variables (above) but I get the same valgrind message every time. Any ideas? Thanks.
you call
char readbuf[len + 1];
and then later
readbuf[len + 1] = '\0';
wouldn't that overflow the array?
Well, you are declaring your readbuf array with non-constant size (i.e with run-time size). This is formally illegal in C++. Such feature exists in C99, but not in C++. Your code will not even compile in a pedantic C++ compiler. And your question is tagged [C++].
But it is quite possible that your compiler implements this feature as a non-standard extension, and that it creates such arrays through an implicit call to new[]. This is why you get the error message that refers to new[], even though you are not using new[] explicitly.
Of course, it is the compiler's responsibility to deallocate such arrays when they end their lifetime. I suspect that the compiler does all it has to do, but the valgrind is confused by something in compiler's actions, which makes it conclude that it is a memory leak.
Moreover, as others already noted, you are making out of bounds access to your array, which can also lead to absolutely any problems at run-time, including the strange report from valgrind.
I found out the problem actually had to do with the Makefile I was using. Thanks for the insight on my slip-up with the char[] bounds though!
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).
According to the Visual C++ runtime there is a heap corruption when calling free in the destructor. But I don't understand why there is a heap corruption, can anyone explain why? The precise error is:
CRT detected that the application wrote to memory after end of heap buffer.
Also, if I ignore the error the program doesn't crash, it keeps running and when I press a key it returns 0.
The class only contains a constructor and destructor and the private vars FILE* target and char* raw_data.
foo::foo (wchar_t* path)
{
size_t size;
target = _wfopen (path, L"rb+");
if (!target) {
char* error = strerror (errno);
printf ("The file could not be opened: %s\n", error);
_exit (1);
}
fseek (target, 0L, SEEK_END);
size = ftell (target);
fseek (target, 0, SEEK_SET);
raw_data = (char*) malloc (size);
size = fread (raw_data, 1, size, target);
raw_data[size] = '\0';
}
foo::~foo ()
{
fclose (target);
free (raw_data);
}
int main ()
{
nbt* klas = new nbt (L"C:\\Users\\Ruben\\level");
puts ("Success?!");
delete klas;
getchar ();
return 0;
}
When writing the NUL terminator as you do:
raw_data[size] = '\0';
... you are using one byte more than the bytes you allocated. There may be other errors but there is definitely an error on this line -- writing to memory you have not allocated is "undefined behaviour" and could explain the crash you're observing.
One sure problem is this code:
raw_data = (char*) malloc (size);
size = fread (raw_data, 1, size, target);
raw_data[size] = '\0';
You cannot access raw_data[size], because it is beyond the allocated size. Indexed access in C/C++ is zero based. As a result, the last element of raw_data that can be accessed with your existing code is raw_data[size-1]. To be able to set the byte which is at offset size to zero you need to change your malloc to:
raw_data = (char*) malloc (size+1);
Since this is a C++ application, you may want to use streams and new/delete instead of FILE pointers and malloc/free.
I need some help figuring out a memory allocation error. I keep getting this error:
Error: Memory could not be allocated.
...when fList is large in the following code:
for (unsigned int ii=0; ii<fList.size(); ii++) {
char *fName = new char[fList[ii].length() + 1];
strcpy(fName, fList[ii].c_str());
err = xInitFile(fName, ii+1);
if(err != 0) {
cout << "FOOBAR" << endl;
}
delete[] fName;
}
fList is a std::vector<std::string>.
The function xInitFile is a C shared library function with the following prototype:
int xInitFile(char *fName, int fHandle)
If fList is small, then everything runs fine. I'm pretty sure the problem lies in how I'm converting the string to a char *, but I can't figure out how to fix it. As far as I can tell, fName is always deleted, so it doesn't appear to be a memory leak. My memory usage doesn't spike while running the code either.
EDIT:
Commenting out err = xInitFile(fName, ii+1); eliminates the error. That means the allocation error is occurring in the xInitFile, right? I didn't think to try this earlier, because I thought the problem was in my code (b/c I'm new to C++).
It's probably frowned upon for one reason or another, but I'd be inclined to instead try strdup.
char *fName = strdup( fList[ii].c_str() );
paired with
free(fName);
I'm writing on c++ in VS2010 Windows 7. I try to read file of size 64 bytes. Here's the code:
BYTE* MyReadFile(FILE *f)
{
size_t result;
BYTE *buffer;
long lSize;
if (f == NULL)
{
fputs ("File error", stderr);
exit (1);
}
fseek (f, 0, SEEK_END);
lSize = ftell (f);
rewind (f);
//buffer = (BYTE*) malloc (sizeof(char)*lSize);
buffer = new BYTE[lSize];
if (buffer == NULL)
{
fputs ("Memory error", stderr);
exit (2);
}
result = fread (buffer, 1, lSize, f);
if (result != lSize)
{
fputs ("Reading error",stderr);
exit (3);
}
fclose (f);
return buffer;
}
When I get file size it is 64, but when I allocate memory for it with new BYTE[lSize] I get 80 bytes of space and thus strange sequence ээээ««««««««оюою is added to the end of buffer. Can you please tell me how to handle this?
There is an important difference between the number of bytes you have allocated, and the number of bytes that you see.
If lsize is 64, you have indeed allocated yourself 64 bytes. This does not mean that behind the screen the C++ run time will have asked exactly 64 bytes to Windows. In practice memory managers ask slightly more memory so they are able to do their own homework. Often these extra bytes are allocated BEFORE the pointer you get back from new/malloc so you will never see them.
However, that is not your problem. The problem is that you read 64 bytes from file using fread. There is no way that fread knows what kind of data you are reading. It could be a struct, a char buffer, a set of doubles, ... It just reads these bytes for you.
This means that if the file contains the characters "ABC" you will get exactly "ABC" back. BUT, in C, strings should be nul-terminated, so if you pass this buffer to printf, it will continue to scan memory until it finds a nul-character.
So, to solve your problem, allocate 1 byte more, and set the last byte to the nul character, like this:
buffer = new BYTE[lSize+1];
buffer[lSize] = '\0';
What is behind and above is called sentinel.It is used to check if your code does not exceed boundary of allocated memory.When your program overwrite this values, CRT library will report debug messages when you release your buffer.
Look here : http://msdn.microsoft.com/en-us/library/ms220938%28v=vs.80%29.aspx
Although this may look like a memory problem, its actually a printing problem (as #Mystical pointed out). You need to put a null termination if you are going to print out anything as a string, else memory will be wildy read till one is encountered (which is UB).
Try this instead:
buffer = new BYTE[lSize + 1];
if (buffer == NULL)
{
fputs ("Memory error", stderr);
exit (2);
}
result = fread (buffer, 1, lSize, f);
if (result != lSize)
{
fputs ("Reading error",stderr);
exit (3);
}
buffer[lSize] = '\0';
It'll ensure there is a null terminator at the end of the returned buffer.
When memory is allocated, it is not on a per byte basis. Instead it is allocated in aligned blocks of 8 or 16 bytes (possibly with a header at the start, before the pointer). This is usually not a problem unless you create lots (many millions) of little objects. This doesn't have to be a problem in C and isn't even a major problem in Java (which doesn't support array of objects or objects allocated on the stack).
I'm writing a Windows Service that allocates memory dynamically. I tried both c++'s new operator and C's malloc. They return (probably valid) pointer but when I try to dereference it the program crashes with Windows saying:
The instruction at "0x77c478ac"
referenced memory at "0x00cb9001". The
memory could not be "read".
BTW I guess the pointer is valid because the referenced memory is not NULL (0x00cb9001).
EDIT: Here is the code
/* This is a thread procedure that is
called when connection arrives
and its purpose is to serve as a
regular expression server.
*/
void threadProc(LPVOID *ptr){
SOCKET accSock = (SOCKET) *ptr;
void * foundPtr;
int recvdBytes;
char * literalPtr;
u_long iMode = 0;
literalPtr = new char [4096]; //this may cause the problem
//We allocate 4kb but in fact the first 2 kbs will be for
//for the literal string, the next 2 kb are for the result
//that must be returned
ioctlsocket(accSock, FIONBIO, &iMode); //the "parent" socket was nonblocking
if(literalPtr){
recvdBytes = recv(accSock, (literalPtr+1), 2048, 0); //BTW, recv returns -1
foundPtr = regexp_cmp(literalPtr, fBuffer, 0); //program crashes when calling this function
if(!foundPtr){
*(literalPtr+2048) = (int) 0;
send(accSock, (char *) (literalPtr+2048), 4, 0); //sending 4 NULLs
}
else {
send(accSock, (char *) (literalPtr+2048), 2048, 0);
}
shutdown (accSock, 0);
delete[] literalPtr;
return;
}
It's pretty funny, you have the answer commented in your code. recv returns -1, indicating that no bytes were read and there is an error, (why not check errno and see what the problem is?) and then you call regexp_cmp anyway on an uninitialized buffer. No wonder it crashes.
As a second point, your code it overly complex. For example, the buffer size is fixed. Why bother newing it? You can keep the buffer on the stack. Why share the same buffer for two different purposes? Just allocate 2 buffers; one for send and the other for recv. Then you don't need to deal with possibly problematic pointer math.
I'm assuming regexp_cmp(literalPt... treats lineralPt as a string: that string is not null terminated ( I can't see any code effort to terminate that string ) so the function simply overrun that buffer looking for the '\0' that never comes...