Reputation: 101
I'm working on a cryptography project and our cipher will need to be able to read and write to a file. One of my partner's implemented the reading capability, and now we're running into an odd problem. Our program runs correctly and without error if no output file is supplied by the user, but segfaults after completion (at return 0) if an output file is supplied. However the program ONLY segfaults on my machine. My team members are running OS X and Fedora, whereas I'm running Ubuntu, if that matters. All of us are compiling with the c++11, though I'm technically specifying c++0x.
int main(int argc, char** argv)
{
std::string usageWarning = "usage: [-i/--input fileName] [-o/--output fileName]
[- k/--key 32bitKey] [-n/--nonce numEncryptions]";
int nonce = 1;
std::string inputFile;
std::string outputFile;
std::string key;
bool hasInputFile = false;
bool hasOutputFile = false;
bool hasKey = false;
std::ofstream out;
if (argc < 2) {
std::cerr << usageWarning << std::endl;
return 1;
}
//Parse command line input
for( int i = 1; i < argc; i++ ) {
if (0 == strncmp(argv[i], "-n", 2) || 0 == strncmp(argv[i], "--nonce", 7)) {
i = i + 1;
nonce = std::stof(argv[i]);
}
else if (0 == strncmp(argv[i], "-i", 2) || 0 == strncmp(argv[i], "--input", 7)) {
i = i + 1;
inputFile = argv[i];
hasInputFile = true;
}
else if (0 == strncmp(argv[i], "-o", 2) || 0 == strncmp(argv[i], "--output", 8)) {
i = i + 1;
outputFile = argv[i];
out.open(outputFile);
std::streambuf *coutbuf = std::cout.rdbuf(); //save old buf
std::cout.rdbuf(out.rdbuf());
hasOutputFile = true;
}
else if (0 == strncmp(argv[i], "-k", 2) || 0 == strncmp(argv[i], "--key", 5)) {
i = i + 1;
key = argv[i];
hasKey = true;
}
else {
std::cerr << "Unrecognized option." << std::endl;
std::cerr << usageWarning << std::endl;
return 1;
}
}
Serpent serpent;
unsigned char testKey[] = {0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00};
unsigned char plaintext[16] =
{0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00};
if (hasKey) {
unsigned char new_key[32];
int index = 0;
for (int i = 0; i < key.length() - 2; i++) {
std::stringstream ss;
ss << std::hex << key[i] << key[i+1];
int n;
ss >> n;
unsigned char x = (unsigned char)n;
new_key[index] = x;
index += 1;
i += 1;
}
memcpy(testKey, new_key, sizeof(testKey));
}
if (hasInputFile) {
unsigned char new_plaintext[16];
std::ifstream in(inputFile);
unsigned char x;
int index = 0;
std::string temp_string = "";
while (in >> std::noskipws >> x) {
std::cout << "X: " << std::hex << x << std::endl;
temp_string += x;
if (temp_string.length() == 2) {
std::stringstream ss;
ss << std::hex << temp_string;
int n = 0;
ss >> n;
unsigned char y = (unsigned char)n;
new_plaintext[index] = y;
index += 1;
temp_string = "";
}
}
// Set plaintext to be theplaintext we read in from file
memcpy(plaintext, new_plaintext, sizeof(plaintext));
}
else {
}
serpent.setKeySize(sizeof(testKey)/sizeof(*testKey));
serpent.setKey(testKey);
serpent.generateSubKeys();
std::cout << "TESTING" << std::endl;
int encryptionRound = 0;
while (encryptionRound < nonce) {
std::cout << std::dec << "================================ ROUND <<
encryptionRound << " ================================\n" << std::endl;
serpent.encrypt(plaintext);
std::cout << std::dec << "============================ END ROUND " <<
encryptionRound << " ============================\n"<< std::endl;
encryptionRound++;
}
if (hasOutputFile){
out.close();
}
return 0;
}
I ran Valgrind and got the following output, but I'm very inexperienced with io business and don't know what to do with the information.
==3131== Memcheck, a memory error detector
==3131== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==3131== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==3131== Command: ./SerpentOpt -n 1 -o output.txt
==3131==
==3131== Invalid read of size 8
==3131== at 0x4EC7328: std::ostream::flush() (in /usr/lib/x86_64-
linux gnu/libstdc++.so.6.0.16)
==3131== by 0x4E97F9B: std::ios_base::Init::~Init() (in /usr/lib/x86_64-linux-
gnu/libstdc++.so.6.0.16)
==3131== by 0x5385900: __run_exit_handlers (exit.c:78)
==3131== by 0x5385984: exit (exit.c:100)
==3131== by 0x536B773: (below main) (libc-start.c:258)
==3131== Address 0x7fefffd88 is just below the stack ptr. To suppress, use: --
workaround-gcc296-bugs=yes
==3131==
==3131==
==3131== Process terminating with default action of signal 11 (SIGSEGV)
==3131== Bad permissions for mapped region at address 0x4224580
==3131== at 0x4224580: ??? (in /lib/x86_64-linux-gnu/ld-2.15.so)
==3131== by 0x4EC732D: std::ostream::flush() (in /usr/lib/x86_64-linux-
gnu/libstdc++.so.6.0.16)
==3131== by 0x4E97F9B: std::ios_base::Init::~Init() (in /usr/lib/x86_64-linux-
gnu/libstdc++.so.6.0.16)
==3131== by 0x5385900: __run_exit_handlers (exit.c:78)
==3131== by 0x5385984: exit (exit.c:100)
==3131== by 0x536B773: (below main) (libc-start.c:258)
==3131==
==3131== HEAP SUMMARY:
==3131== in use at exit: 0 bytes in 0 blocks
==3131== total heap usage: 10,745 allocs, 10,745 frees, 493,629 bytes allocated
==3131==
==3131== All heap blocks were freed -- no leaks are possible
==3131==
==3131== For counts of detected and suppressed errors, rerun with: -v
==3131== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Segmentation fault (core dumped)
Thanks for any and all help!
Upvotes: 0
Views: 1491
Reputation: 5083
Here's where you're causing yourself grief:
out.open(outputFile);
std::streambuf *coutbuf = std::cout.rdbuf(); //save old buf
std::cout.rdbuf(out.rdbuf());
Now there are two objects that both point to the same buf. Guess what happens after one object is destroyed and cleans up its resources and then the second object starts to do its destructor.
Upvotes: 2