ferror leads to access violation - c++

I get an Access Violation when calling ferror(f). The thing is I check that f isn't a null pointer. I'm also able to read out of the file, before I get the Access Violation. It happens in the bzip library from http://www.bzip.org, (which is only modified, so that it is possible to build, eg. disable error and remove the multiple main functions).
Here is the my main
int main() {
int e = 0;
int *error = &e;
FILE *f = fopen("./test", "r"); //open file
if (f == NULL) { //Changed, as beforehand both checks happend at the same time
//However the programm passes both checks
std::cout << "f* is NULL\n";
exit(1);
}
if (ferror(f)) {
std::cerr << "Can't open the file " << ferror(f) << '\n';
exit(1);
}
char *c = char[20];
fread(c, 1, 20, f); // Here we can read succesfully out of the file
std::cout << c;
BZFILE* bzfile = BZ2_bzReadOpen(error, f, 1, 0, NULL, 0); //The failing function call
}
Here is the function out of the library which fails:
BZFILE* BZ_API(BZ2_bzReadOpen)
( int* bzerror,
FILE* f,
int verbosity,
int small,
void* unused,
int nUnused )
{
bzFile* bzf = NULL;
int ret;
BZ_SETERR(BZ_OK);
if (f == NULL || //A check in the function itself, which also passes
(small != 0 && small != 1) ||
(verbosity < 0 || verbosity > 4) ||
(unused == NULL && nUnused != 0) ||
(unused != NULL && (nUnused < 0 || nUnused > BZ_MAX_UNUSED)))
{ BZ_SETERR(BZ_PARAM_ERROR); return NULL; };
if (ferror(f)) // Here is the access violation
{ BZ_SETERR(BZ_IO_ERROR); return NULL; };
}
The specific error is
Exception thrown at 0x0003E5C4 in wikiParser.exe: 0xC0000005: Access violation executing location 0x0003E5C4.
I tried moving the program to a different pc, however the same error still occurs. The pointer isn't NULL; there are two checks for that, and I can call ferror myself, without it being an access violation.

if(f == NULL || ferror(f)) // Check that f isn't NULL nor has an Error
std::cerr << "Can't open the file " << ferror(f) << '\n';
In other words, if f== NULL then cerr << ferror(f).
No wonder it blows up.

Related

Clearing buffer while reading in binary data from a server in C++

I have a server that sends raw binary data to print a "map" that a user must traverse through, however, I am having trouble clearing out my buffer after each line read and thus keep getting residual data printed at the end of the shorter lines. In the screenshot below you can see my output on the left, and what the output should be on the right. What is the best way to solve this? I feel like I am missing something but cant seem to find a solution.
And the code that is reading/printing this is below:
char* mapData = NULL;
string command = "command> ";
size_t dataSize = 0;
while(mapData != command.c_str()) {
unsigned char* buffer = (unsigned char*) &dataSize;
connection = read(mySocket, buffer, 8);
if(connection == -1 || connection < 0) {
cerr << "**Error: could not read text size" << endl;
return 1;
}
mapData = (char*)malloc(dataSize);
buffer = (unsigned char*) mapData;
while((connection = read(mySocket, buffer, dataSize)) != -1) {
if(connection == -1 || connection < 0) {
cerr << "**Error: could not read text size" << endl;
return 1;
}
if(dataSize != 1) {
cout << buffer;
}
free(buffer);
buffer = NULL;
}
}
You are ignoring the return value of read() to know how many bytes are in the buffer.
read() returns the actual number of bytes that were read, which may be fewer than you requested. So you need to call read() in a loop until you have read all of the bytes you are expecting, eg:
int readAll(int sock, void *buffer, size_t buflen)
{
unsigned char* pbuf = reinterpret_cast<unsigned char*>(buffer);
while (buflen > 0) {
int numRead = read(sock, pbuf, buflen);
if (numRead < 0) return -1;
if (numRead == 0) return 0;
pbuf += numRead;
buflen -= numRead;
}
return 1;
}
Also, after reading the buffer, you are treating it as if it were null-terminated, but it is not, which is why you get extra garbage in your output.
More importantly, mapData != command.c_str() will ALWAYS be true, so your while loop iterates indefinitely (until a socket error occurs), which is not what you want. You want the loop to end when you receive a "command> " string instead.
mapData is initially NULL, and c_str() NEVER returns NULL, so the loop ALWAYS iterates at least once.
Then you allocate and free mapData but don't reset it to NULL, so it is left pointing at invalid memory. Which doesn't really matter, since your while loop is just comparing pointers. c_str() will NEVER return a pointer to memory that mapData ever points to.
To end your loop correctly, you need to compare the contents of mapData after reading, not compare its memory address.
Try this instead:
char *mapData = NULL;
uint64_t dataSize = 0;
const string command = "command> ";
bool keepLooping = true;
do {
if (readAll(mySocket, &dataSize, sizeof(dataSize)) <= 0) {
cerr << "**Error: could not read text size" << endl;
return 1;
}
if (dataSize == 0)
continue;
mapData = new char[dataSize];
if (readAll(mySocket, mapData, dataSize) <= 0) {
cerr << "**Error: could not read text" << endl;
delete[] mapData;
return 1;
}
cout.write(mapData, dataSize);
keepLooping = (dataSize != command.size()) || (strncmp(mapData, command.c_str(), command.size()) != 0);
delete[] mapData;
}
while (keepLooping);
Alternatively:
string mapData;
uint64_t dataSize = 0;
const string command = "command> ";
do {
if (readAll(mySocket, &dataSize, sizeof(dataSize)) <= 0) {
cerr << "**Error: could not read text size" << endl;
return 1;
}
mapData.resize(dataSize);
if (dataSize > 0) {
if (readAll(mySocket, &mapData[0], dataSize) <= 0) {
cerr << "**Error: could not read text" << endl;
return 1;
}
cout << mapData;
}
}
while (mapData != command);
like #eozd pointed out, calling malloc and free in your loop is a bad idea since you use return statements. Your code may leak memory. You should ensure you call free before returns. Even better, you could declare your buffer outside of while loop, and use break instead of return, and call free if there was en error
Looking at your solution, it seems that the communication protocol involves sending data size first, followed by the actual data. How is data size written to the wire? You may need to convert it from network byte order.
To debug, you could print out the value of dataSize before every read to make sure that it is what you expect
You should clear the buffer too. Add:
memset(mapData, 0, dataSize);
after the malloc.

String written to child process corrupted?

I want to execute a program in a child process. The program works when I run it directly in the terminal: It waits for some input and Control+D/EOF has to be send before it processes it.
In my code below the program does not seem to receive a string properly, it seems as if it only sees some part or nothing at all when it receives EOF which also seems to happen several times even though I only send it once.
If anyone can tell me what is going wrong here?
int main(int argc, char** argv) {
int pipes[2][2]; //pipe[0] read, pipe[1] write
#define PARENT_READ_FD ( pipes[1][0] )
#define PARENT_WRITE_FD ( pipes[0][1] )
#define CHILD_READ_FD ( pipes[0][0] )
#define CHILD_WRITE_FD ( pipes[1][1] )
// pipes for parent to write and read
assert( (pipe(pipes[1])) == 0 );
assert( (pipe(pipes[0])) == 0 );
int pid = fork();
if(pid == 0) {
char *argv[]={"/workspace/osm/overpass/osm3s_v0.7.51/bin/osm3s_query", "--db-dir=$DB_DIR"};
assert( (dup2(CHILD_READ_FD, STDIN_FILENO)) != -1);
assert( (dup2(CHILD_WRITE_FD, STDOUT_FILENO)) != -1);
close(CHILD_READ_FD);
close(CHILD_WRITE_FD);
close(PARENT_READ_FD);
close(PARENT_WRITE_FD);
execv(argv[0], argv);
} else if(pid > 0) {
char buffer[1000];
int count;
close(CHILD_READ_FD);
close(CHILD_WRITE_FD);
int query_size = strlen(query.c_str()) + 1;
int succesful_write = write(PARENT_WRITE_FD, &query, query_size);
assert(succesful_write==query_size);
close(PARENT_WRITE_FD);
// Read from child’s stdout
while( count = read(PARENT_READ_FD, buffer, sizeof(buffer)-1) > 0){
cerr << buffer << endl;
}
} else {
cerr << "Could not fork child process" << endl;
exit(EXIT_FAILURE);
}
}
The error output from the program is for example (it changes every time the program is run):
line 1: parse error: Unknown type "�"
line 1: parse error: An empty query is not allowed
line 1: parse error: Unknown type "n"
line 1: parse error: An empty query is not allowed
line 1: parse error: Unknown type "�"
...

Wrong error code

I'm using portaudio to play a sound. I want to be able to select the output via the UI. I managed it like that :
PaError err = Pa_Initialize();
if( err != paNoError )
return false;
qDebug() <<"Port audio succeed initialization !";
int numDevices;
numDevices = Pa_GetDeviceCount();
if( numDevices <= 0 )
{
qDebug() << "ERROR: Pa_CountDevices returned " << numDevices;
return false;
}
const PaDeviceInfo *deviceInfo;
bool isThereOutput = false;
int i = 0;
while(i < numDevices and !isThereOutput)
{
deviceInfo = Pa_GetDeviceInfo( i );
isThereOutput = (deviceInfo->maxOutputChannels > 0);
i++;
}
if(!isThereOutput)
{
qDebug() << "No output device";
return false;
}
PaError errorOpening;
if(outputDevice != "")
{
PaStreamParameters outputDeviceInfo;
int numDevices = Pa_GetDeviceCount();
const PaDeviceInfo *deviceInfo;
for(int i = 0; i<numDevices; i++ )
{
deviceInfo = Pa_GetDeviceInfo( i );
if(deviceInfo->maxOutputChannels > 0 && deviceInfo->name == outputDevice)
{
outputDeviceInfo.device = i;
outputDeviceInfo.channelCount = 1;
outputDeviceInfo.sampleFormat = paInt8;
outputDeviceInfo.suggestedLatency = deviceInfo->defaultLowOutputLatency;
}
}
if(outputDeviceInfo.channelCount > 1)
{
errorOpening = Pa_OpenStream(&stream, NULL, &outputDeviceInfo, SAMPLE_RATE, FRAME_PER_BUFFER, paNoFlag, audioCallback, this);
}
}
if(outputDevice == "" or errorOpening != paNoError)
{
if(errorOpening != paNoError)
qDebug() << "Can't open selected device ("<< outputDevice <<"), switching to the default one. Error : " << Pa_GetErrorText(errorOpening);
errorOpening = Pa_OpenDefaultStream( &stream,
0, /* no input channels */
1, /* mono output */
paInt8, /* 8 bits output */
SAMPLE_RATE,
FRAME_PER_BUFFER, /* frames per buffer, i.e. the number
of sample frames that PortAudio will
request from the callback. Many apps
may want to use
paFramesPerBufferUnspecified, which
tells PortAudio to pick the best,
possibly changing, buffer size.*/
audioCallback, /* this is your callback function */
this ); /*This is a pointer that will be passed to
your callback*/
}
if(errorOpening != paNoError)
return false;
if(Pa_StartStream( stream ) != paNoError)
return false;
And it fails :
Can't open selected device ( "Sortie intégr" ), switching to the default one. Error : Invalid error code (value greater than zero)
But I can't figure why OpenStream fails with a strange error code and Pa_OpenDefaultStream works like a charm.
So :
Why does it fails ?
Why does it throw a wrong error code ?
I assume you use C++ (though there are several curious and and or in your code.)
If your for loop didn't find any PaDeviceInfo which satisfies eviceInfo->maxOutputChannels > 0 && deviceInfo->name == outputDevice, then your outputDeviceInfo is left un-initialized. That means its channelConnect can have any values including large negative values. Then Pa_OpenStream isn't invoked and your errorOpening is also left un-initialized. I bet that's the reason of Invalid error code (value greater than zero) when you feed it into Pa_GetErrorText().

C SHMGET returning values other than -1 on failure

I'm trying to create the equivalent to this Windows code with Unix Shared Memory, however instead of returning -1 as the docs say and setting the errno value, when the shared memory hasn't been created yet, it returns 65537.
I'm just trying to get it to loop until the memory has been created in the other process and then return the id and 'connect to it'.
Windows Code:
HANDLE hClientSlot = NULL;
unsigned long long* clientSlot;
while(hClientSlot == NULL)
{
hClientSlot = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, CLIENTSLOTNAME);
if(hClientSlot == NULL)
{
std::cout << "Could not open Client Slot file mapping object:" << GetLastError() << std::endl;
}
}
clientSlot = reinterpret_cast<unsigned long long*>( MapViewOfFile(hClientSlot, FILE_MAP_ALL_ACCESS, 0, 0, 1 * sizeof(unsigned long long)) );
if(!clientSlot)
{
std::cout << "Error: Failed to map Client Slot!" << std::endl;
}
Unix Code: EDIT: Added Key_T stuff based on #Zack's feedback
unsigned long long* clientSlot;
int clientSlotID = -1;
key_t slotKey;
slotKey = ftok(CLIENTSLOTNAME, ID);
while(clientSlotID == -1)
{
clientSlotID = shmget(slotKey, sizeof(unsigned long long), 0666);
}
clientSlot = (unsigned long long*) shmat(clientSlotID, NULL, 0);
if(!clientSlot)
{
std::cout << "Error: Failed to map client slot!" << std::endl;
}

Downloading Binary Files With Wininet

I am currently programming a simple program, I want to distribute to my friends. What I am trying to accomplish, is to write some external binary files to a buffer from the internet, upon starting the program. To do this, I am using windows internet(wininet). Currently, I am using InternetReadFile to write the file to a buffer which I use later in the program. However, the File is not read completely, as in, the resulting size is much smaller than the size of the file on the server, when it should be the same.
I would like to do this, without using any external libraries.
Any idea of what could solve my problem?
Thanks,
Andrew
The documentation makes the following remarks:
InternetReadFile operates much like the base ReadFile function, with a few exceptions. Typically, InternetReadFile retrieves data from an HINTERNET handle as a sequential stream of bytes. The amount of data to be read for each call to InternetReadFile is specified by the dwNumberOfBytesToRead parameter and the data is returned in the lpBuffer parameter. A normal read retrieves the specified dwNumberOfBytesToRead for each call to InternetReadFile until the end of the file is reached. To ensure all data is retrieved, an application must continue to call the InternetReadFile function until the function returns TRUE and the lpdwNumberOfBytesRead parameter equals zero.
Basically, there is no guarantee that the function to read exactly dwNumberOfBytesToRead. Check out how many bytes were actually read using the lpdwNumberOfBytesRead parameter.
Moreover, as soon as the total file size is larger than dwNumberOfBytesToRead, you will need to invoke the call multiple times. Because it cannot read more than dwNumberOfBytesToRead at once.
If you have the total file size in advance, the loop takes the following form:
::DWORD error = ERROR_SUCCESS;
::BYTE data[SIZE]; // total file size.
::DWORD size = 0;
::DWORD read = 0;
do {
::BOOL result = ::InternetReadFile(stream, data+size, SIZE-size, &read);
if ( result == FALSE ) {
error = ::GetLastError();
}
}
while ((error == ERROR_SUCCESS) && (read > 0) && ((size+=read) < SIZE));
// check that `SIZE` was correct.
if (size != SIZE) {
}
If not, then you need to write the data in the buffer to another file instead of accumulating it.
EDIT (SAMPLE TEST PROGRAM):
Here's a complete program that fetches StackOverflow's front page. This downloads about 200K of HTML code in 1K chunks and the full page is retrieved. Can you run this and see if it works?
#include <Windows.h>
#include <Wininet.h>
#include <iostream>
#include <fstream>
namespace {
::HINTERNET netstart ()
{
const ::HINTERNET handle =
::InternetOpenW(0, INTERNET_OPEN_TYPE_DIRECT, 0, 0, 0);
if ( handle == 0 )
{
const ::DWORD error = ::GetLastError();
std::cerr
<< "InternetOpen(): " << error << "."
<< std::endl;
}
return (handle);
}
void netclose ( ::HINTERNET object )
{
const ::BOOL result = ::InternetCloseHandle(object);
if ( result == FALSE )
{
const ::DWORD error = ::GetLastError();
std::cerr
<< "InternetClose(): " << error << "."
<< std::endl;
}
}
::HINTERNET netopen ( ::HINTERNET session, ::LPCWSTR url )
{
const ::HINTERNET handle =
::InternetOpenUrlW(session, url, 0, 0, 0, 0);
if ( handle == 0 )
{
const ::DWORD error = ::GetLastError();
std::cerr
<< "InternetOpenUrl(): " << error << "."
<< std::endl;
}
return (handle);
}
void netfetch ( ::HINTERNET istream, std::ostream& ostream )
{
static const ::DWORD SIZE = 1024;
::DWORD error = ERROR_SUCCESS;
::BYTE data[SIZE];
::DWORD size = 0;
do {
::BOOL result = ::InternetReadFile(istream, data, SIZE, &size);
if ( result == FALSE )
{
error = ::GetLastError();
std::cerr
<< "InternetReadFile(): " << error << "."
<< std::endl;
}
ostream.write((const char*)data, size);
}
while ((error == ERROR_SUCCESS) && (size > 0));
}
}
int main ( int, char ** )
{
const ::WCHAR URL[] = L"http://stackoverflow.com/";
const ::HINTERNET session = ::netstart();
if ( session != 0 )
{
const ::HINTERNET istream = ::netopen(session, URL);
if ( istream != 0 )
{
std::ofstream ostream("output.txt", std::ios::binary);
if ( ostream.is_open() ) {
::netfetch(istream, ostream);
}
else {
std::cerr << "Could not open 'output.txt'." << std::endl;
}
::netclose(istream);
}
::netclose(session);
}
}
#pragma comment ( lib, "Wininet.lib" )