1. // http://stackoverflow.com/questions/13463375/memory-corruption
  2.  
  3. #include <QtDebug>
  4. #include <QByteArray>
  5. #include <QLibrary>
  6. #include <QDir>
  7.  
  8. static inline QString LAT1(const char *str, const int len = -1) {
  9.     return QString::fromLatin1(str, len);
  10. }
  11.  
  12. template <typename T>
  13. static inline QByteArray createByteArray(const T *from, const int numElements) {
  14.     return QByteArray(reinterpret_cast<const char*>(from), sizeof(T) * numElements);
  15. }
  16.  
  17. /*
  18. // This one uses types and functions directly from <windows.h>.
  19. // (Static linking.)
  20.  
  21. #define WIN32_LEAN_AND_MEAN
  22. #define WIN32_EXTRA_LEAN
  23. #include <windows.h>
  24.  
  25. QByteArray fingerprintStatic() {
  26.     const DWORD kMaxPath = 260 + 1;  // MAX_PATH + 1
  27.     wchar_t path[kMaxPath]       = {0};
  28.     wchar_t name[kMaxPath]       = {0};
  29.     wchar_t fileSystem[kMaxPath] = {0};
  30.     DWORD serial = 0;
  31.     DWORD maximumComponentLength = 0;
  32.     DWORD fileSystemFlags = 0;
  33.  
  34.     QDir::toNativeSeparators(QDir::rootPath()).toWCharArray(path);
  35.     if (FAILED(GetVolumeInformationW(path, name, kMaxPath, &serial, &maximumComponentLength,
  36.                                      &fileSystemFlags, fileSystem, kMaxPath))) {
  37.         qWarning("GetVolumeInformationW() failed: %u", static_cast<uint32_t>(GetLastError()));
  38.         return QByteArray();
  39.     }
  40.  
  41.     return createByteArray<wchar_t>(fileSystem, wcslen(fileSystem));
  42. }
  43. */
  44.  
  45. // This one resolves functions from Kernel32.dll dynamically and uses standard types.
  46. // (Dynamic linking.)
  47. QByteArray fingerprintDynamic() {
  48.     const uint32_t kMaxPath = 260 + 1;  // MAX_PATH + 1
  49.     wchar_t path[kMaxPath]       = {0};
  50.     wchar_t name[kMaxPath]       = {0};
  51.     wchar_t fileSystem[kMaxPath] = {0};
  52.     uint32_t serial = 0;
  53.     uint32_t maximumComponentLength = 0;
  54.     uint32_t fileSystemFlags = 0;
  55.  
  56.     QLibrary kernel32("kernel32");
  57.     typedef uint32_t (*fnGetLastError)(void);
  58.     typedef bool (*fnGetVolumeInformationW)(const wchar_t*, wchar_t*, uint32_t, uint32_t*, uint32_t*,
  59.                                             uint32_t*, wchar_t*, uint32_t);
  60.     fnGetVolumeInformationW GetVolumeInformationW = reinterpret_cast<fnGetVolumeInformationW>(kernel32.resolve("GetVolumeInformationW"));
  61.     fnGetLastError GetLastError = reinterpret_cast<fnGetLastError>(kernel32.resolve("GetLastError"));
  62.  
  63.     if (!GetVolumeInformationW) {
  64.         qWarning(LAT1("GetVolumeInformationW() not resolved: %1").arg(kernel32.errorString()).toLatin1().constData());
  65.         return QByteArray();
  66.     }
  67.     else if (!GetLastError) {
  68.         qWarning(LAT1("GetLastError() not resolved: %1").arg(kernel32.errorString()).toLatin1().constData());
  69.         return QByteArray();
  70.     }
  71.  
  72.     QDir::toNativeSeparators(QDir::rootPath()).toWCharArray(path);
  73.     bool apiCall = GetVolumeInformationW(path, name, kMaxPath, &serial, &maximumComponentLength,
  74.                                          &fileSystemFlags, fileSystem, kMaxPath);
  75.     if (!apiCall)
  76.         qWarning(LAT1("GetVolumeInformationW() failed: %1").arg(GetLastError()).toLatin1().constData());
  77.  
  78.     // At this point, fileSystem is correct and contains
  79.     // L"NTFS"
  80.  
  81.     // ONLY HAPPENS IN DEBUG MODE
  82.     //
  83.     // After this call memory becomes corrupted. wcslen() is not a problem.
  84.     // And createByteArray<>() is ok too, I believe.
  85.     //size_t len;  // But if I change stack a bit (like uncomment this line),
  86.                    // result will be correct, so I guess it's related to memory offset.
  87.     return createByteArray<wchar_t>(fileSystem, wcslen(fileSystem));
  88.  
  89. //    return createByteArray<wchar_t>(path, wcslen(path)) +
  90. //           createByteArray<wchar_t>(name, wcslen(name)) +
  91. //           createByteArray<wchar_t>(fileSystem, wcslen(fileSystem)) +
  92. //           createByteArray<uint32_t>(&serial, 1) +
  93. //           createByteArray<uint32_t>(&maximumComponentLength, 1) +
  94. //           createByteArray<uint32_t>(&fileSystemFlags, 1);
  95. }
  96.  
  97. void print(const QByteArray &bytes) {
  98.     qDebug() << QString::fromWCharArray(reinterpret_cast<const wchar_t*>(bytes.constData()));
  99.     qDebug() << bytes.size() << "bytes" << bytes.toHex();
  100.     qDebug() << "";
  101. }
  102.  
  103. int main(int, char**)
  104. {
  105. //    qDebug() << "static";
  106. //    print(fingerprintStatic());
  107.  
  108.     qDebug() << "dynamic";
  109.     print(fingerprintDynamic());
  110.  
  111.     return 0;
  112. }