2

I'm writing a big application and i recently included there my new module for working with files. It has simple functions of writing integers and strings, it was tested to be perfect on Red Hat. It does exactly what i want.

Here's the implementation of the functions there:

int CFile_open(CFile* owner, char* filename, char* mode) {
    owner->file = fopen(filename, mode);
    if (owner->file == NULL) {
        return 0;
    } else {
        return 1;
    }
}

int CFile_close(CFile* owner) {
    if (owner->file == NULL) {
        return 0;
    } else {
        if (fclose(owner->file) ) {
            return 1;
        } else {
            return 0;
        }
    }
}

int CFile_writeInt(CFile* owner, int num) {
    if (owner->file == NULL) {
        return 0;
    } else {
        if (fwrite(&num, sizeof(int), 1, owner->file)) {
            return 1;
        } else {
            return 0;
        }
    }
}

int CFile_writeString(CFile* owner, char* str) {
    if (owner->file == NULL) {
        return 0;
    } else {
        char b = strlen(str);
        if (fwrite(&b, sizeof(char), 1, owner->file)) {
            for (int i=0; i<=b; i++) {
                fwrite(&str[i], sizeof(char), 1, owner->file);
            }
        } else {
            return 0;
        }
    }
}

These functions are being used in the wrapper-function and then being executed in my application.
Here's that function:

void fileWrite(void* data) {
    CList* list = (CList*)data;
    CNode* node = list->first;
    CData* info = NULL;
    CFile* f = (CFile*)malloc(sizeof(CFile));
    f->init = CFile_init;
    f->init(f);

    if (list->length == 0) {
        printf("%s\n", "The list is empty!");
        wait();
    } else {
        int i = 1;

        if (f->open(f, (char*)"./f", (char*)"w")) {
            while (node) {
                info = node->getData(node);

                if (f->writeInt(f, info->getNum(info))) {
                    if (f->writeString(f, info->getAdr(info))) {
                        if (f->writeString(f, info->getPh(info))) {
                            printf("%s%d\n", "Wrote item #", i);
                            i++;
                        } else {
                            printf("%s%d\n", "Error writing Phone of item #", i);
                        }
                    } else {
                        printf("%s%d\n", "Error writing Adress of item #", i);
                    }
                } else {
                    printf("%s%d\n", "Error writing Number of item #", i);
                }

                node = node->next;
            }
            if (f->close(f)) {
                printf("%s\n", "Wrote successfully");
                wait();
            }
        }
        free(f);
    }
}

The problematic spot is the f->close(f) at the very end of the function.
If i don't close the file, everything works flawlessly. But if i do, i'm getting the following error:

*** Error in 'a.out': free(): invalid next size (normal): 0x0859c320 ***

However, despite the application crash, it does close the file, and the info i wrote to it is correct and not corrupted.

But i can't figure out why am i getting the error. I close the file only once (as you may see from the function), and i also tried commenting the free(f) line.
Also if i call fclose(f->file) there i get the same error, so that's not the close() function issue.

I assume that the rest of the application works (and worked before i added the function) perfectly except for the line where i close the file.

The reason i mentioned RedHat is because it was working perfectly there, but when i recompiled it under ArchLinux (also tried Debian) - it won't close the file. Same compiler versions were used everywhere.

I compile it with g++ if that matters, but i also have the same issue with clang++.

I also tried running it with valgrind and it says nothing about files, or i just couldn't find the right keys for that. Perhaps you know?

So do you have any ideas on what's going on and how to fix it? I was staring at the code for literally 3 hours already and i can't figure it out for the life of me.


Test case:

info->getNum() returns integer "11" (assigned during input)
info->getAdr() returns dynamically allocated char array "aa" (allocated and assigned during input)
info->getPh() returns dynamically allocated char array "bb" (allocated and assigned during input)

I can test these values using other functions in my application, so i'm 100% confident they are correct.

Then i just evoke the fileWrite() function.

keke
  • 105
  • 2
  • 2
  • 14
  • Present your _testcase_. – Lightness Races in Orbit Oct 30 '14 at 19:45
  • It's hard to suggest something useful without seeing what the `CFile` member functions do. – R Sahu Oct 30 '14 at 19:50
  • Edited the question. I don't know if that would help because the only things i'm getting from outside the function are the values that i can check and i'm sure they are correct. – keke Oct 30 '14 at 19:51
  • R Sahu, the `CFile` functions are listed in the first code block of the post. – keke Oct 30 '14 at 19:52
  • What if you comment out while loop, leaving only opening and closing file? – Tomashu Oct 30 '14 at 19:57
  • Tomashu, no, it's still the same. All the `CList` related operations are most probably correct as well. However i only create one `CNode` in my application while testing and `CList::first` points to that single `CNode`, so there might not be an error. – keke Oct 30 '14 at 20:01
  • Take a look at this http://stackoverflow.com/a/14636125/867354 – Tomashu Oct 30 '14 at 20:10
  • Tomashu, i googled before asking, and i've seen this one (it made me download valgrind), but i couldn't apply it to my case. I don't allocate anything after closing the file. Following the application scenario, all there's after the end of this function is a bunch of `printf()`s and a single `scanf()`. – keke Oct 30 '14 at 20:27
  • It have to be before closing. Heap/stack corruption often crash in weird locations, completly unrelated. – Tomashu Oct 30 '14 at 21:37
  • This is tagged as `c++` but it looks more like C with a home-rolled object oriented programming approach... is C++ the correct tag? – AAT Oct 30 '14 at 22:07
  • Yes, it is. I'm just being a freak. – keke Oct 31 '14 at 04:02
  • Tomashu, hm, i will double check the code before the close then. However, after the crash, it does it's job. It writes correct info to a correct file in a correct order. – keke Oct 31 '14 at 04:10

1 Answers1

3

At a first glance:

In CFile_writeString there's an off-by-one error. for (int i=0; i<=b; i++) should terminate at i<b. The &str[b] will result in undefined behaviour.

BTW, result type of strlen is size_t, not char.

I don't know if that's the cause of your problem, though.

C-B
  • 56
  • 4
  • Thanks for pointing this out. I fixed it. But, apparently, the issue still persists. – keke Oct 31 '14 at 07:49
  • Try compiling with `-Wall -Wextra` to leverage compiler diagnostics and fix all warnings. If that still does not resolve your issue try to reduce the test case to a minimal example needed to reproduce the problem (see [http://stackoverflow.com/help/mcve](http://stackoverflow.com/help/mcve)). – C-B Oct 31 '14 at 11:12
  • 2
    I've seen your post over at reddit and had a look at [https://bitbucket.org/owyou/simplebd](https://bitbucket.org/owyou/simplebd). One additional issue: You reserve space for 5 menu items, but call `CMenu_addItem` 6 times, resulting in another off-by-one accessing `owner->list[len]`. – C-B Oct 31 '14 at 12:11
  • 3
    Fixing the one with the list eliminated the error. Thanks for noticing. I'm always getting confused about array indexes when i also need to handle the user input. – keke Oct 31 '14 at 16:23
  • 2
    I have a similar problem, checked answer here and found out I also have a similar boundary issue. Thanks guys – 1a1a11a Jun 18 '16 at 13:48