[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