0

I am making a password manager for a school project which comes with huge WARRANTY VOID IF USED AT ALL stickers all over it. The aim is to be able to do CRUD on the data in the program and write it to disk in an "encrypted" form.

I have a dynamic array of base and child types which i can write to memory using Library::WriteToFiles() and read from memory using Library::ReadFromFiles(). This all works great in my debug setup where i always write and then immediately read back into memory.

int main() {
bool debug = true;
if (debug) {

    Library library = Library();
    library.Add(new Password("Outside", "yobro"));
    library.Add(new Password("Wut", "idk"));
    library.Add(new UsernameLogin("Yo", "M8", "James May"));

    library.Print();

    cout << endl;

    library.WriteToFiles();
    library.ReadFromFiles();

    library.Print();
    return 0;

}

But when i comment out the Write call i get a bad access from this bit in the read function

void Library::ReadFromFiles() {
this->Clear();

ifstream baseFileObject;
ifstream usrNameFileObject;

baseFileObject.open("base.txt");
while (true) {
    if (baseFileObject.eof()) break;
    Password* password = new Password();
    baseFileObject.read((char*) password, sizeof(*password));
    if ( ! password->IsEmpty()) { // <- Trying to call IsEmpty() throws a BAD ACCESS
        Add(password);
    }
}
baseFileObject.close();

When i try calling other functions in the Password class that are not virtual they run just fine. IsEmpty() also runs just fine before the read. I checked the pointer and it stays the same throughout. The files open correctly and the data is read into the object.

What confuses me the most is why it works when i have already written in that execution. If reading into an object like that corrupts the vtable then why does it work sometimes?

EDIT: The password class has 3 variables. Two strings and a bool. No pointers. Here are the public functions. I'm only having problems with the virtual functions.

public:
virtual int Type();
virtual string ToString();
virtual bool IsEmpty();
virtual bool Encrypt(unsigned int key);
virtual bool Decrypt(unsigned int key);

[[nodiscard]] bool isEncrypted() const;

[[nodiscard]] const string &getPassword() const;
void setPassword(const string &newPassword);

[[nodiscard]] const string &getLocation() const;
void setLocation(const string &newLocation);

int PasswordStrength();
itsZazzles
  • 33
  • 4
  • `baseFileObject.read((char*) password, sizeof(*password));` will only work if the Password class has no pointers member variables, and no non-trivial member variable objects. – Eljay Nov 26 '19 at 14:42
  • How is the Password class defined? – user253751 Nov 26 '19 at 14:46
  • It has 3 private variables. Two strings and a bool. The data is always read. It's just the virtual functions that i am missing. – itsZazzles Nov 26 '19 at 14:47
  • *Two strings and a bool.* -- Then this whole thing `baseFileObject.read((char*) password, sizeof(*password));` is invalid. You can't read into non-POD types like this. This could never work -- assume the `std::string`'s had 1000 characters in them. What would `sizeof(*password)` give you? It isn't going to be a 1000 or greater. It will be the actual size of the `Password` class, not the data it holds at runtime. Read up on [object serialization](https://stackoverflow.com/questions/523872/how-do-you-serialize-an-object-in-c) – PaulMcKenzie Nov 26 '19 at 15:20
  • `string`s are non-trivial (which one meaning of that is they internally may contain pointers). Having any `virtual` methods is also non-trivial. – TheUndeadFish Nov 26 '19 at 15:22
  • OK i understand. I guess my test data is just short enough to fit inside the `sizeof(*password)`. I should shift strategy entirely. But i still don't understand why my virtual functions _work_ when i have previously written to the file in the same execution. – itsZazzles Nov 26 '19 at 15:36
  • *But i still don't understand why my virtual functions work* -- Undefined behavior. Change compiler, compiler options, etc. and you don't know what results you will get. – PaulMcKenzie Nov 26 '19 at 15:52
  • How can a function returning a reference be used? What are the guarantees? – curiousguy Dec 27 '19 at 09:48

1 Answers1

0

It has been made clear that this line:

baseFileObject.read((char*) password, sizeof(*password));

Just doesn't work for my use case. Serialization is the obvious, scalable, ideal solution here but since this is a school project i am going for old fashioned writing text to a file and parsing it back in using sstream or something like that.

Thanks for the help :)

itsZazzles
  • 33
  • 4