Qt SimpleCrypt crashes: access violation - qt

I want to write a file.
At first I have to encrypt the string "Banking;k1OI<]uH|V&r" using SimpleCrypt.
SimpleCrypt's code:
QString SimpleCrypt::encryptToString(const QString& plaintext)
{
QByteArray plaintextArray = plaintext.toUtf8();
QByteArray cypher = encryptToByteArray(plaintextArray);
QString cypherString = QString::fromLatin1(cypher.toBase64());
return cypherString;
}
The crash happens at m_keyParts.isEmpty() with an access violation
QByteArray SimpleCrypt::encryptToByteArray(QByteArray plaintext)
{
if (m_keyParts.isEmpty()) {
qWarning() << "No key set.";
m_lastError = ErrorNoKeySet;
return QByteArray();
}
// [...]
// Rest of the code
}
Does somebody know what to do?
Thanks in advance
Edit
Stacktrace:
Accessibles.exe!QVector::isEmpty() Zeile 91 C++
Accessibles.exe!SimpleCrypt::encryptToByteArray(QByteArray plaintext)
Zeile 55 C++ Accessibles.exe!SimpleCrypt::encryptToString(const
QString & plaintext) Zeile 118 C++ Accessibles.exe!DataStream::save()
Zeile 40 C++
Calling code:
textStream << p_simpleCrypt->encryptToString(QString("%1;%2\n").arg(bundle‌​->category).arg(bund‌​le->categoryId));

Related

How to wait for Async lamda function to finish before returning value in a QT Web Assembly

so I wrote a programm for my thesis in Qt and now i am supposed to turn it into a working web assembly, which wasnt a real problem except for the filedownload part. I rewrote my filedownload method from:
QString costumfile::read(QString filename){
QString fileName = QFileDialog::getOpenFileName(nullptr, filename, "", "Text Files (*.txt )");
QFile file(filename);
qDebug()<<filename<<"filename";
if(!file.open(QFile::ReadOnly |
QFile::Text))
{
qDebug() << " Could not open the file for reading";
return "";
}
QTextStream in(&file);
QString myText = in.readAll();
//qDebug() << myText;
file.close();
return myText;
}
To this:
QString costumfile::read(QString filename)
{
QMessageBox msgBox;
QString textUser="Open" + filename;
msgBox.setText(textUser);
msgBox.exec();
QString text="hallo";
qDebug()<<filename;
auto fileContentReady = [&](const QString &fileName, const QString &fileContent) {
if (fileName.isEmpty()) {
msgBox.setText("Error");
msgBox.exec();
} else {
text=fileContent;
qDebug()<<text<<"texstis";
return fileContent;
}
return fileContent;
};
QFileDialog::getOpenFileContent(".txt", fileContentReady);
}
and the problem is that the return doesnt wait for the lambda function because its asynch...
I then tried using eventloops which works fine in the Destop applikation but isnt supported in the webassembly Applikation.
So does someone have a good idea how to wait for the fileContentReady Function?
As far as I know, Qt for WebAssembly currently does not support waiting using event loops (at least Qt 6.2 does not). See Qt wiki:
"Nested event loops are not supported. Applications should not call e.g. QDialog::exec() or create a new QEventLoop object."
https://wiki.qt.io/Qt_for_WebAssembly
So you would have to modify your method to handle the asynchronous call. What I mean is that whatever you want to do with the file, you can write directly into the fileContentReady lambda you have. If this is a generic function, you can let the caller register a done callback to execute when the file is ready. Something like:
QString costumfile::read(QString filename,
const std::function<void(const QString&)>& done)
{
...
auto fileContentReady = [=](const QString &fileName, const QString &fileContent) {
if (fileName.isEmpty()) {
// Report error
} else {
text=fileContent;
qDebug()<<text<<"texstis";
done(text);
}
};
QFileDialog::getOpenFileContent(".txt", fileContentReady);
}
// When calling costumfile::read
read(filename, [=] (const QString& text) {
// Do something with `text`
});
Also, about the usage of QMessageBox exec(). This can also cause problems as it internally creates a nested event loop which is not yet supported in Qt for WebAssembly. Instead use the show() method.
auto msgBox = new QMessageBox();
msgBox->setText(textUser);
connect(msgBox, &QMessageBox::finished, &QMessageBox::deleteLater);
msgBox->show();

QBtyeArray QDataStream qCompress to file adding extra leading bytes

Qt/C++ program has a function which writes an objects data (_token) to a file as follows:
QFile f( _tokenFile);
if (!f.open( QIODevice::WriteOnly)) {
qDebug() << "Unable to open token file for writing" << f.errorString();
return false;
}
QByteArray tokenBa;
QDataStream ds( &tokenBa, QIODevice::WriteOnly);
ds << _token;
tokenBa = qCompress( tokenBa);
f.write( tokenBa);
f.close();
The _token is an instance of the following struct:
struct Token {
QString accessToken;
QString refreshToken;
QString clientSecret;
QString authCode;
QTime expiryTime;
enum AuthState {
A_Invalid,
A_RequestAuth,
A_Authenticated,
};
AuthState state;
Token() : state( A_Invalid) {}
bool isValid() const {
if (accessToken.isEmpty() ||
refreshToken.isEmpty()) {
return false;
}
return true;
}
void inValidate() {
accessToken.clear();
refreshToken.clear();
clientSecret.clear();
authCode.clear();
expiryTime = QTime();
}
void cleanUp() {
accessToken.clear();
refreshToken.clear();
clientSecret.clear();
authCode.clear();
expiryTime = QTime();
}
};
When the file is saved it has 4 extra bytes at the start which render the file as a invalid zlib file.
0000000 0000 5e01 9c78 904d 4f5d 5082 871c fa9f
0000020 353e 25cd 6975 2c2f d563 4c2c 62b8 cad1
We can see above bytes 5-6 are 9C 78 which is the zlib signature, but the 4 bytes before these are the issue.
To check the compressed data is correct I do the following:
dd if=file.token bs=1 skip=4 | openssl zlib -d
And this produces the expected result (for testing).
The problem is in the application reading this data back into the data object:
QFile f( _tokenFile);
if (!f.exists()) {
qDebug() << "Token file doesn't exist" << f.fileName();
return false;
}
if (!f.open( QIODevice::ReadOnly)) {
qDebug() << "Unable to open token file for reading" << f.errorString();
return false;
}
QByteArray tokenBa = f.readAll();
f.close();
if (tokenBa.isEmpty()) {
qDebug() << "Token file is empty.";
return false;
}
tokenBa = qUncompress( tokenBa);
QDataStream ds( &tokenBa, QIODevice::ReadOnly);
ds >> _token;
This returns null - because of the leading 4 extraneous bytes. I could put some code in to skip these 4 leading bytes, but how do I know it will always be 4 bytes? I'd like to instead have certainly that the files data is all zlib compressed.
My question is how to avoid those bytes being saved in the first place so that on re-read the format is known to be zlib type?
You can't avoid them since they're needed for qUncompress later on:
Note: If you want to use this function to uncompress external data that was compressed using zlib, you first need to prepend a four byte header to the byte array containing the data. The header must contain the expected length (in bytes) of the uncompressed data, expressed as an unsigned, big-endian, 32-bit integer.

Cannot open QFile for appending/readwrite

I am trying to use the following code to open the existing file to append data at it's end:
void AddPharmacyForm::addInsertToFile(QString insert)
{
QFile inserts(":/new/prefix1/insertstatements.txt");
if(!inserts.exists())
qDebug() << "File does not exist";
if(inserts.isOpen())
qDebug() << "file is open";
if(inserts.open(QFile::ReadWrite | QFile::Text))
{
// Another workaround- could not open file with append flag
qDebug() << "im here!";
QString currentInserts;
QTextStream out(&inserts);
out >> currentInserts;
out << endl << insert;
inserts.close();
}
else
{
QMessageBox::information(this, tr("Error"), tr("Cannot add new pharmacy! "
"Please contact program designer."
));
qDebug() << "error code: " + QString::number(inserts.error());
return;
}
}
The output of this code is the QMessageBox with the error and in qDebug it produces following line:
"error code: 5"
It does not give notice about file not existing and file being open. I have also tried opening file with different flags: QFile::ReadWrite, QFile::append, QFile::WriteOnly and the same modes within QIODevice. The error code is still the same. When I am opening the file from another class, the file opens without errors (it is not an access error).
What might be causing this problem?
There's no support for writing into the resource system, whether implemented using Qt's resource system or native to the platform. Your application typically has no right to modify its own executable, or the application bundle, or its installation location - it'd be a security risk if it did since bugs in networking code could be easily exploited to infect your user's system. So what you're trying to do is just a bad idea.
Instead, store the modified resources in your application's data folder, and revert to reading from the resource if the file doesn't exist. It is also probably not very wise to append to a file if the file is small: such appends are not atomic and can partially fail, leaving the file corrupted. Using a QSaveFile is guaranteed to either completely succeed or to fail without modifying any data.
An example implementation follows. The src.close() is not necessary to close the file, as QFile will automatically close upon destruction, as it is a proper resource-managing C++ class. By closing it earlier we ensure minimal use of the file descriptor - a finite system resource.
// https://github.com/KubaO/stackoverflown/tree/master/questions/resource-bypass-43044268
#include <QtCore>
const char kInsertsFile[] = ":/insertstatements.txt";
QString toWritableName(const QString & qrcFileName) {
Q_ASSERT (qrcFileName.startsWith(":/"));
QFileInfo info(qrcFileName);
return
QStandardPaths::writableLocation(QStandardPaths::DataLocation)
+ info.path().mid(1) + '/' + info.fileName();
}
QString toReadableName(const QString & qrcFileName) {
Q_ASSERT (qrcFileName.startsWith(":/"));
auto writable = toWritableName(qrcFileName);
return QFileInfo(writable).exists() ? writable : qrcFileName;
}
bool setupWritableFile(QSaveFile & dst, QIODevice::OpenMode mode = {}) {
Q_ASSERT (dst.fileName().startsWith(":/"));
Q_ASSERT (mode == QIODevice::OpenMode{} || mode == QIODevice::Text);
QFile src(toReadableName(dst.fileName()));
dst.setFileName(toWritableName(dst.fileName()));
if (!src.open(QIODevice::ReadOnly | mode))
return false;
auto data = src.readAll();
src.close(); // Don't keep the file descriptor tied up any longer.
QFileInfo dstInfo(dst.fileName());
if (!dstInfo.dir().exists() && !QDir().mkpath(dstInfo.path()))
return false;
if (!dst.open(QIODevice::WriteOnly | mode))
return false;
return dst.write(data) == data.size();
}
bool addInsertToFile(const QString & insert) {
QSaveFile file(kInsertsFile);
if (!setupWritableFile(file, QIODevice::Text))
return false;
if (true) {
// Alternative 1
QTextStream s(&file);
s << insert << '\n';
} else {
// Alternative 2
file.write((insert + '\n').toLocal8Bit());
}
return file.commit();
}
QStringList readInserts() {
QFile file(toReadableName(kInsertsFile));
if (!file.open(QIODevice::ReadOnly))
return {};
return QString::fromLocal8Bit(file.readAll()).split('\n', QString::SkipEmptyParts);
}
int main(int argc, char ** argv) {
QCoreApplication app{argc, argv};
app.setApplicationName("resource-bypass-42044268");
qDebug() << "Original Inserts:" << readInserts();
auto rc = addInsertToFile("NewInsert");
qDebug() << "Modification status:" << rc;
qDebug() << "Current Inserts:" << readInserts();
}
When you use the Qt Resource System (qrc files) to add files for your project, they are compiled directly into the binary of your application, so are therefore readonly. As the documentation states: -
Resource data can either be compiled into the binary and thus accessed immediately in application code, or a binary resource can be created and at a later point in application code registered with the resource system.
And...
Currently, Qt always stores the data directly in the executable, even on Windows, macOS, and iOS, where the operating system provides native support for resources. This might change in a future Qt release.

QFile write a WAV header writes only 4 byte data

I'm writing a WAV recorder, using QFile as backbone. However, when I fill my Wav struct, and try to write it to my QFile it writes only "RIFF", I viewed it with unix's od -cb 1.wav. Here is the samle code:
wavwriter.cpp
Wav::Wav(const char *fname, QFile* parent)
: QFile(fname, parent),
m_fname(fname)
{
setFileName(fname);
bool res = this->open(QIODevice::ReadWrite);
if (res) {
std::cout << "File opened for RW\n";
}
}
Wav::~Wav()
{
}
void Wav::writeHeader(const WavHdr* hdr)
{
write((char*)hdr);
flush();
}
void Wav::appendData(const QByteArray &data)
{
m_data.append(data);
}
QByteArray Wav::getWavData()
{
return m_data;
}
And the usage is as follows:
WavHdr hdr;
hdr.bits_per_sample = 8;
hdr.riff[0] = 'R';
hdr.riff[1] = 'I';
hdr.riff[2] = 'F';
hdr.riff[3] = 'F';
hdr.sample_rate = 8;
hdr.fmt[0] = 'f';
hdr.fmt[1] = 'm';
hdr.fmt[2] = 't';
m_wavs[i]->writeHeader(&hdr);
The WavHdr has the following setup:
struct WavHdr
{
char riff[4];
qint32 file_size;
char wave[4];
char fmt[4];
char len[3];
qint16 type;
quint16 format;
qint32 sample_rate;
qint32 sr_bs_channs;
quint8 bits_per_sample;
char data[4];
qint32 fsize;
};
You can't dump WavHdr to disk directly.
The way you use the write method only makes sense for zero-terminated strings. It will stop writing at the first zero-valued byte. A WavHdr is not a null-terminated string.
You cannot assume that the struct has any particular representation in memory. The compiler is free to arrange that structure the way it sees fit. Not only it can pad and align the members arbitrarily, it can also rearrange them. So that's a non-portable anti-pattern: it may happen to work on some compilers, on others it will be thoroughly broken.
Your WavHdr is wrong.
See here for reference. I've included a correct header structure below.
You probably wish to use a QSaveFile.
When saving files, you usually intend the file writing to be atomic: either it succeeds and you get a complete, valid WAV file, or it fails and nothing changes on disk (e.g. an existing file is not overwritten and corrupted). That's what QSaveFile is designed for.
You probably want your wave class to use an I/O device, but not be one.
I/O can be done with just an instance of a QIODevice*: you'll then be able to easily write the data to in-memory buffers, files, network sockets, etc. The user of your class should be free to choose what particular device to use.
Instead, use QDataStream to write the header in a portable way:
struct WavHdr
{
constexpr static quint32 k_riff_id = 0x46464952;
constexpr static quint32 k_wave_format = 0x45564157;
constexpr static quint32 k_fmt_id = 0x20746d66;
constexpr static quint32 k_data_id = 0x61746164;
// RIFF
quint32 chunk_id = k_riff_id;
quint32 chunk_size;
quint32 chunk_format = k_wave_format;
// fmt
quint32 fmt_id = k_fmt_id;
quint32 fmt_size;
quint16 audio_format;
quint16 num_channels;
quint32 sample_rate;
quint32 byte_rate;
quint16 block_align;
quint16 bits_per_sample;
// data
quint32 data_id = k_data_id;
quint32 data_size;
};
bool write(QIODevice * dev, const WavHdr & h) {
QDataStream s{dev};
s.setByteOrder(QDataStream::LittleEndian); // for RIFF
s << h.chunk_id << h.chunk_size
<< h.chunk_format;
s << h.fmt_id << h.fmt_size
<< h.audio_format
<< h.num_channels
<< h.sample_rate
<< h.byte_rate
<< h.block_align
<< h.bits_per_sample;
s << h.data_id << h.data_size;
return s.status() == QDataStream::Ok;
}

Unable to read shared memory data using boost created by Qt

I've created a Qt shared memory program to write a string into shared memory. Now After writing, I need to read it from Boost program. I tried using simple programs, but I couldn't read the string using Boost interprocess.
Here is the Qt code that is writing into the shared memory. And I'm double checking if the string is written by reading from the shared memory from the same program.
void CDialog::loadString()
{
if(sharedMemory.isAttached())
{
if(!sharedMemory.detach())
{
lbl->setText("Unable to detach from Shared Memory");
return;
}
}
lbl->setText("Click on Top Button");
char sString[] = "my string";
QBuffer buffer;
buffer.open(QBuffer::ReadWrite);
QDataStream out(&buffer);
out << sString;
int size = buffer.size();
qDebug() << size;
if(!sharedMemory.create(size))
{
lbl->setText("Unable to create shared memory segment");
qDebug() << lbl->text();
}
sharedMemory.lock();
char *to = (char *) sharedMemory.data();
const char *from = buffer.data();
memcpy(to, from, qMin(sharedMemory.size(), size));
sharedMemory.unlock();
char * str;
QDataStream in(&buffer);
sharedMemory.lock();
buffer.setData((char *)sharedMemory.constData(), sharedMemory.size());
buffer.open(QBuffer::ReadOnly);
in >> str;
sharedMemory.unlock();
qDebug() << str;
}
And I'm reading it from boost using the same key which I've provided in the Qt program.
Below is the Boost program code -
int main()
{
boost::interprocess::shared_memory_object shdmem(boost::interprocess::open_only, "Highscore", boost::interprocess::read_only);
boost::interprocess::offset_t size;
if (shdmem.get_size(size))
std::cout << "Shared Mem Size: " << size << std::endl;
boost::interprocess::mapped_region region2(shdmem, boost::interprocess::read_only);
char *i2 = static_cast<char *>(region2.get_address());
std::cout << i2 << std::endl;
return 0;
}
Kindly help me in reading the shared memory data from Boost program.
Thank you.
From the Qt docs:
Warning: QSharedMemory changes the key in a Qt-specific way. It is therefore currently not possible to use the shared memory of non-Qt applications with QSharedMemory.
You will probably need to use Boost on both sides.

Resources