[Kst] branches/work/kst/portto4/kst/src/datasources/ascii
Peter Kümmel
syntheticpp at gmx.net
Mon Oct 8 20:39:01 UTC 2012
SVN commit 1319753 by kuemmel:
QVarLengthArray throws when out of memory
also work around a Qt bug, C&P from merge request:
OOM: don't overwrite valid pointer with NULL
After a exception is thrown in resize QVarLengthArray has an
invalid state with ptr == 0. On the next resize call when qMalloc
returns a valid pointer oldPtr is 0 and it could crash in
qMemCopy because the pointer to the source is 0.
For example:
int GB = 1024*1024*1024;
while (qMalloc(GB) != 0) {}
QVarLengthArray<char, 0> arr;
try {
arr.resize(GB);
} catch(const std::bad_alloc&) {
arr.resize(1024);
}
M +12 -18 asciisource.cpp
M +6 -7 asciisource.h
--- branches/work/kst/portto4/kst/src/datasources/ascii/asciisource.cpp #1319752:1319753
@@ -42,6 +42,9 @@
// disable QASSERT when using [] on data
#define KST_DONT_CHECK_INDEX_IN_DEBUG
+// simulate out of memory scenario
+//#define KST_TEST_OOM
+
using namespace Kst;
@@ -194,6 +197,11 @@
is(new DataInterfaceAsciiString(*this)),
iv(new DataInterfaceAsciiVector(*this))
{
+#ifdef KST_TEST_OOM
+ // eat the giga bytes
+ while (qMalloc(1024*1024*1024) != 0) {}
+#endif
+
setInterface(is);
setInterface(iv);
@@ -480,22 +488,11 @@
}
//-------------------------------------------------------------------------------------------
-bool AsciiSource::couldAllocate(int bytes) const
+void AsciiSource::clearFileBuffer(bool forceDelete)
{
- void* ptr = qMalloc(bytes);
- if (ptr) {
- qFree(ptr);
- return true;
- }
- return false;
-}
-
-//-------------------------------------------------------------------------------------------
-void AsciiSource::clearFileBuffer()
-{
// force deletion of internal allocated memory if any
const int memoryOnStack = sizeof(FileBuffer) - sizeof(QVarLengthArray<char, 0>);
- if (_fileBuffer->capacity() > memoryOnStack) {
+ if (forceDelete || _fileBuffer->capacity() > memoryOnStack) {
delete _fileBuffer;
_fileBuffer = new FileBuffer;
}
@@ -517,14 +514,11 @@
// find a smaller allocatable size
clearFileBuffer();
- int realloc_size = n / 2;
- _fileBuffer->resize(realloc_size);
- while (_fileBuffer->size() != realloc_size && realloc_size > 0) {
+ int realloc_size = n / 4;
+ while (!resizeBuffer(*_fileBuffer, realloc_size) && realloc_size > 0) {
realloc_size /= 2;
- _fileBuffer->resize(realloc_size);
}
clearFileBuffer();
- realloc_size /= 2; // while reading available memory could shrink, just be sure
if (realloc_size == 0) {
QMessageBox::warning(0, "Error while reading ascii file", "File could not be read because not enough memory is available.");
return 0;
--- branches/work/kst/portto4/kst/src/datasources/ascii/asciisource.h #1319752:1319753
@@ -88,8 +88,7 @@
QVarLengthArray<int, KST_PREALLOC> _rowIndex;
typedef QVarLengthArray<char, KST_PREALLOC> FileBuffer;
FileBuffer* _fileBuffer;
- void clearFileBuffer();
- bool couldAllocate(int bytes) const;
+ void clearFileBuffer(bool forceDelete = false);
int _bufferedS;
int _bufferedN;
@@ -258,13 +257,13 @@
template<class T>
bool AsciiSource::resizeBuffer(T& buffer, int bytes)
{
- if (!couldAllocate(bytes))
- return false;
-
- const int oldSize = buffer.size();
+ try {
buffer.resize(bytes);
- if (buffer.size() == oldSize)
+ } catch (const std::bad_alloc&) {
+ // work around Qt bug
+ clearFileBuffer(true);
return false;
+ }
return true;
}
More information about the Kst
mailing list