2023-09-19 15:49:22 +03:00
|
|
|
//===-- WinFunctions.cpp - Windows Functions for other platforms --*- C++
|
|
|
|
//-*-===//
|
2018-06-25 23:04:13 +03:00
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file defines Windows-specific functions used in the codebase for
|
|
|
|
// non-Windows platforms.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#ifndef _WIN32
|
|
|
|
#include <fcntl.h>
|
2018-07-17 21:46:57 +03:00
|
|
|
#include <map>
|
2018-07-17 16:19:40 +03:00
|
|
|
#include <string.h>
|
2018-06-25 23:04:13 +03:00
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#include "dxc/Support/WinFunctions.h"
|
[Linux] WinAdapter: Remove virtual dtors from IUnknown to fix vtable ABI (#3793)
* WinAdapter: Remove virtual dtors from IUnknown to fix vtable ABI
The vtable for `IUnknown` and its subclasses contain two deletion
pointers when compiled on non-Windows systems with `IUnknown` from
`WinAdapter.h`:
vtable for 'DxcLibrary' @ 0x7ffff7cbc5f8 (subobject @ 0x5555556bb9e0):
[0]: 0x7ffff6a56d40 <DxcLibrary::QueryInterface(_GUID const&, void**)>
[1]: 0x7ffff6a56d20 <DxcLibrary::AddRef()>
[2]: 0x7ffff6a56d30 <DxcLibrary::Release()>
[3]: 0x7ffff6b36bc0 <IUnknown::~IUnknown()> // Complete object destructor
[4]: 0x7ffff6a57130 <DxcLibrary::~DxcLibrary()> // Deleting destructor
[5]: 0x7ffff6a56d50 <DxcLibrary::SetMalloc(IMalloc*)>
[6]: 0x7ffff6a56d60 <DxcLibrary::CreateBlobFromBlob(IDxcBlob*, unsigned int, unsigned int, IDxcBlob**)>
... More DxcLibrary virtual functions
This shifts the the pointers for functions for all subclasses, and is
[annoying] to deal with in otherwise cross-platform applications using
DirectXShaderCompiler as library. `dxcompiler.dll` compiled on/for
Windows without `WinAdapter.h` does not suffer this problem, and only
has three function pointers for `IUnknown`.
Fortunately, it is easily solved by removing the virtual destructor from
`IUnknown`. LLVM enables `-Wnon-virtual-dtor` that warns against
classes with virtual methods but no virtual destructor, though this
warning is best not enabled akin to Windows builds where `IUnknown` from
`windows.h` (`unknwn.h`) results in the same warning on MSVC ([1]/[2]).
[annoying]: https://github.com/Traverse-Research/hassle-rs/blob/1e624792fc3a252ac7788e3c1c5feda52887272f/src/unknown.rs
[1]: https://github.com/microsoft/DirectXShaderCompiler/issues/3783#issuecomment-844189358
[2]: https://godbolt.org/z/hKPT6ThEf
* WinAdapter: Make `IUnknown` and `IMalloc` pure-virtual classes
`IUnknown` in Windows' `unknwn.h` and `IMalloc` in `ObjIdl.h` are marked
as pure virtual, and are best marked as such in `WinAdapter` for
non-Windows platforms too [1]. Only the shim for `IMalloc` was relying
on the default refcounting implementation, all other subclasses either
contain pure-virtual methods themselves or provide an implementation for
`AddRef`/`Release` as required. Likewise the default implementation for
`IMalloc` was only instantiated once by `CoGetMalloc`, and has been
moved into a local class implementing the `IMalloc` interface instead.
[1]: https://github.com/microsoft/DirectXShaderCompiler/pull/3793#issuecomment-846459741
* WinAdapter: Add three missing virtual functions to `IMalloc` interface
To prevent unexpected vtable breakage, add the missing functions from
the [documentation]. Note that they are listed in the wrong order, the
right order is retrieved from the `ObjIdl.h` header and implementations
for `IMalloc` in DirectXShaderCompiler. All implementations are now
properly using the `override` keyword too, to enforce virtual method
existence in the base class.
[documentation]: https://docs.microsoft.com/en-us/windows/win32/api/objidl/nn-objidl-imalloc
* Make all WinAdapter destructions explicit
This prevents warnings about non-virtual destructor usage that trip up
the Linux build. It represents status quo on Windows.
Co-authored-by: Greg Roth <grroth@microsoft.com>
2022-10-13 20:19:39 +03:00
|
|
|
#include "dxc/Support/microcom.h"
|
2018-06-25 23:04:13 +03:00
|
|
|
|
|
|
|
HRESULT StringCchPrintfA(char *dst, size_t dstSize, const char *format, ...) {
|
|
|
|
va_list args;
|
|
|
|
va_start(args, format);
|
2018-07-16 17:51:13 +03:00
|
|
|
va_list argscopy;
|
|
|
|
va_copy(argscopy, args);
|
2018-06-25 23:04:13 +03:00
|
|
|
// C++11 snprintf can return the size of the resulting string if it was to be
|
|
|
|
// constructed.
|
2023-09-19 15:49:22 +03:00
|
|
|
size_t size =
|
|
|
|
vsnprintf(nullptr, 0, format, argscopy) + 1; // Extra space for '\0'
|
2018-06-25 23:04:13 +03:00
|
|
|
if (size > dstSize) {
|
|
|
|
*dst = '\0';
|
|
|
|
} else {
|
2018-07-16 17:51:13 +03:00
|
|
|
vsnprintf(dst, size, format, args);
|
2018-06-25 23:04:13 +03:00
|
|
|
}
|
2018-07-16 17:51:13 +03:00
|
|
|
va_end(argscopy);
|
2018-06-25 23:04:13 +03:00
|
|
|
va_end(args);
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
HRESULT UIntAdd(UINT uAugend, UINT uAddend, UINT *puResult) {
|
|
|
|
HRESULT hr;
|
|
|
|
if ((uAugend + uAddend) >= uAugend) {
|
|
|
|
*puResult = (uAugend + uAddend);
|
|
|
|
hr = S_OK;
|
|
|
|
} else {
|
|
|
|
*puResult = 0xffffffff;
|
2018-06-26 22:05:08 +03:00
|
|
|
hr = ERROR_ARITHMETIC_OVERFLOW;
|
2018-06-25 23:04:13 +03:00
|
|
|
}
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
HRESULT IntToUInt(int in, UINT *out) {
|
|
|
|
HRESULT hr;
|
|
|
|
if (in >= 0) {
|
|
|
|
*out = (UINT)in;
|
|
|
|
hr = S_OK;
|
|
|
|
} else {
|
|
|
|
*out = 0xffffffff;
|
2018-06-26 22:05:08 +03:00
|
|
|
hr = ERROR_ARITHMETIC_OVERFLOW;
|
|
|
|
}
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
HRESULT SizeTToInt(size_t in, int *out) {
|
|
|
|
HRESULT hr;
|
2023-09-19 15:49:22 +03:00
|
|
|
if (in <= INT_MAX) {
|
2018-06-26 22:05:08 +03:00
|
|
|
*out = (int)in;
|
|
|
|
hr = S_OK;
|
2023-09-19 15:49:22 +03:00
|
|
|
} else {
|
2018-06-26 22:05:08 +03:00
|
|
|
*out = 0xffffffff;
|
|
|
|
hr = ERROR_ARITHMETIC_OVERFLOW;
|
2018-06-25 23:04:13 +03:00
|
|
|
}
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
HRESULT UInt32Mult(UINT a, UINT b, UINT *out) {
|
|
|
|
uint64_t result = (uint64_t)a * (uint64_t)b;
|
|
|
|
if (result > uint64_t(UINT_MAX))
|
2018-06-26 22:05:08 +03:00
|
|
|
return ERROR_ARITHMETIC_OVERFLOW;
|
2018-06-25 23:04:13 +03:00
|
|
|
|
|
|
|
*out = (uint32_t)result;
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
2018-09-26 00:24:59 +03:00
|
|
|
int strnicmp(const char *str1, const char *str2, size_t count) {
|
|
|
|
size_t i = 0;
|
|
|
|
for (; i < count && str1[i] && str2[i]; ++i) {
|
|
|
|
int d = std::tolower(str1[i]) - std::tolower(str2[i]);
|
|
|
|
if (d != 0)
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i == count) {
|
|
|
|
// All 'count' characters matched.
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// str1 or str2 reached NULL before 'count' characters were compared.
|
|
|
|
return str1[i] - str2[i];
|
|
|
|
}
|
|
|
|
|
2018-06-25 23:04:13 +03:00
|
|
|
int _stricmp(const char *str1, const char *str2) {
|
|
|
|
size_t i = 0;
|
|
|
|
for (; str1[i] && str2[i]; ++i) {
|
|
|
|
int d = std::tolower(str1[i]) - std::tolower(str2[i]);
|
|
|
|
if (d != 0)
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
return str1[i] - str2[i];
|
|
|
|
}
|
|
|
|
|
2018-07-17 16:19:40 +03:00
|
|
|
int _wcsicmp(const wchar_t *str1, const wchar_t *str2) {
|
|
|
|
size_t i = 0;
|
|
|
|
for (; str1[i] && str2[i]; ++i) {
|
|
|
|
int d = std::towlower(str1[i]) - std::towlower(str2[i]);
|
|
|
|
if (d != 0)
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
return str1[i] - str2[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
int _wcsnicmp(const wchar_t *str1, const wchar_t *str2, size_t n) {
|
|
|
|
size_t i = 0;
|
|
|
|
for (; i < n && str1[i] && str2[i]; ++i) {
|
|
|
|
int d = std::towlower(str1[i]) - std::towlower(str2[i]);
|
|
|
|
if (d != 0)
|
|
|
|
return d;
|
|
|
|
}
|
2023-09-19 15:49:22 +03:00
|
|
|
if (i >= n)
|
|
|
|
return 0;
|
2018-07-17 16:19:40 +03:00
|
|
|
return str1[i] - str2[i];
|
|
|
|
}
|
|
|
|
|
2023-09-19 15:49:22 +03:00
|
|
|
unsigned char _BitScanForward(unsigned long *Index, unsigned long Mask) {
|
2018-07-17 16:19:40 +03:00
|
|
|
unsigned long l;
|
2023-09-19 15:49:22 +03:00
|
|
|
if (!Mask)
|
|
|
|
return 0;
|
|
|
|
for (l = 0; !(Mask & 1); l++)
|
|
|
|
Mask >>= 1;
|
2018-07-17 16:19:40 +03:00
|
|
|
*Index = l;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2023-09-14 16:59:49 +03:00
|
|
|
HANDLE CreateFile2(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
|
|
|
|
DWORD dwCreationDisposition, void *pCreateExParams) {
|
2018-06-25 23:04:13 +03:00
|
|
|
return CreateFileW(lpFileName, dwDesiredAccess, dwShareMode, pCreateExParams,
|
|
|
|
dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, nullptr);
|
|
|
|
}
|
|
|
|
|
2023-09-14 16:59:49 +03:00
|
|
|
HANDLE CreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
|
|
|
|
void *lpSecurityAttributes, DWORD dwCreationDisposition,
|
|
|
|
DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) {
|
2018-06-25 23:04:13 +03:00
|
|
|
CW2A pUtf8FileName(lpFileName);
|
|
|
|
size_t fd = -1;
|
|
|
|
int flags = 0;
|
|
|
|
|
|
|
|
if (dwDesiredAccess & GENERIC_WRITE)
|
|
|
|
if (dwDesiredAccess & GENERIC_READ)
|
|
|
|
flags |= O_RDWR;
|
|
|
|
else
|
|
|
|
flags |= O_WRONLY;
|
2023-09-19 15:49:22 +03:00
|
|
|
else // dwDesiredAccess may be 0, but open() demands something here. This is
|
|
|
|
// mostly harmless
|
2018-06-25 23:04:13 +03:00
|
|
|
flags |= O_RDONLY;
|
|
|
|
|
|
|
|
if (dwCreationDisposition == CREATE_ALWAYS)
|
|
|
|
flags |= (O_CREAT | O_TRUNC);
|
|
|
|
if (dwCreationDisposition == OPEN_ALWAYS)
|
|
|
|
flags |= O_CREAT;
|
|
|
|
else if (dwCreationDisposition == CREATE_NEW)
|
|
|
|
flags |= (O_CREAT | O_EXCL);
|
|
|
|
else if (dwCreationDisposition == TRUNCATE_EXISTING)
|
|
|
|
flags |= O_TRUNC;
|
|
|
|
// OPEN_EXISTING represents default open() behavior
|
|
|
|
|
|
|
|
// Catch Implementation limitations.
|
2023-09-19 15:49:22 +03:00
|
|
|
assert(!lpSecurityAttributes &&
|
|
|
|
"security attributes not supported in CreateFileW yet");
|
2018-06-25 23:04:13 +03:00
|
|
|
assert(!hTemplateFile && "template file not supported in CreateFileW yet");
|
|
|
|
assert(dwFlagsAndAttributes == FILE_ATTRIBUTE_NORMAL &&
|
|
|
|
"Attributes other than NORMAL not supported in CreateFileW yet");
|
|
|
|
|
2023-09-19 15:49:22 +03:00
|
|
|
while ((int)(fd = open(pUtf8FileName, flags,
|
|
|
|
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) {
|
2018-07-17 16:19:40 +03:00
|
|
|
if (errno != EINTR)
|
|
|
|
return INVALID_HANDLE_VALUE;
|
|
|
|
}
|
2018-06-25 23:04:13 +03:00
|
|
|
|
|
|
|
return (HANDLE)fd;
|
|
|
|
}
|
|
|
|
|
2023-09-14 16:59:49 +03:00
|
|
|
BOOL GetFileSizeEx(HANDLE hFile, PLARGE_INTEGER lpFileSize) {
|
2018-06-25 23:04:13 +03:00
|
|
|
int fd = (size_t)hFile;
|
|
|
|
struct stat fdstat;
|
|
|
|
int rv = fstat(fd, &fdstat);
|
|
|
|
if (!rv) {
|
|
|
|
lpFileSize->QuadPart = (LONGLONG)fdstat.st_size;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-09-14 16:59:49 +03:00
|
|
|
BOOL ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
|
|
|
|
LPDWORD lpNumberOfBytesRead, void *lpOverlapped) {
|
2018-06-25 23:04:13 +03:00
|
|
|
size_t fd = (size_t)hFile;
|
|
|
|
ssize_t rv = -1;
|
|
|
|
|
|
|
|
// Implementation limitation
|
|
|
|
assert(!lpOverlapped && "Overlapping not supported in ReadFile yet.");
|
|
|
|
|
|
|
|
rv = read(fd, lpBuffer, nNumberOfBytesToRead);
|
|
|
|
if (rv < 0)
|
|
|
|
return false;
|
|
|
|
*lpNumberOfBytesRead = rv;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-09-14 16:59:49 +03:00
|
|
|
BOOL WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
|
|
|
|
LPDWORD lpNumberOfBytesWritten, void *lpOverlapped) {
|
2018-06-25 23:04:13 +03:00
|
|
|
size_t fd = (size_t)hFile;
|
|
|
|
ssize_t rv = -1;
|
|
|
|
|
|
|
|
// Implementation limitation
|
|
|
|
assert(!lpOverlapped && "Overlapping not supported in WriteFile yet.");
|
|
|
|
|
|
|
|
rv = write(fd, lpBuffer, nNumberOfBytesToWrite);
|
|
|
|
if (rv < 0)
|
|
|
|
return false;
|
|
|
|
*lpNumberOfBytesWritten = rv;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-09-14 16:59:49 +03:00
|
|
|
BOOL CloseHandle(HANDLE hObject) {
|
2018-06-25 23:04:13 +03:00
|
|
|
int fd = (size_t)hObject;
|
|
|
|
return !close(fd);
|
|
|
|
}
|
|
|
|
|
2018-07-17 21:46:57 +03:00
|
|
|
// Half-hearted implementation of a heap structure
|
2023-09-19 15:49:22 +03:00
|
|
|
// Enables size queries, maximum allocation limit, and collective free at heap
|
|
|
|
// destruction Does not perform any preallocation or allocation organization.
|
2018-07-17 21:46:57 +03:00
|
|
|
// Does not respect any flags except for HEAP_ZERO_MEMORY
|
|
|
|
struct SimpleAllocation {
|
|
|
|
LPVOID ptr;
|
|
|
|
SIZE_T size;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct SimpleHeap {
|
|
|
|
std::map<LPCVOID, SimpleAllocation> allocs;
|
|
|
|
SIZE_T maxSize, curSize;
|
|
|
|
};
|
|
|
|
|
2023-09-19 15:49:22 +03:00
|
|
|
HANDLE HeapCreate(DWORD flOptions, SIZE_T dwInitialSize, SIZE_T dwMaximumSize) {
|
2018-07-17 21:46:57 +03:00
|
|
|
SimpleHeap *simpHeap = new SimpleHeap;
|
|
|
|
simpHeap->maxSize = dwMaximumSize;
|
|
|
|
simpHeap->curSize = 0;
|
|
|
|
return (HANDLE)simpHeap;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL HeapDestroy(HANDLE hHeap) {
|
2023-09-19 15:49:22 +03:00
|
|
|
SimpleHeap *simpHeap = (SimpleHeap *)hHeap;
|
2018-07-17 21:46:57 +03:00
|
|
|
|
2023-09-19 15:49:22 +03:00
|
|
|
for (auto it = simpHeap->allocs.begin(), e = simpHeap->allocs.end(); it != e;
|
|
|
|
it++)
|
2018-07-17 21:46:57 +03:00
|
|
|
free(it->second.ptr);
|
|
|
|
|
|
|
|
delete simpHeap;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
LPVOID HeapAlloc(HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes) {
|
|
|
|
LPVOID ptr = nullptr;
|
2023-09-19 15:49:22 +03:00
|
|
|
SimpleHeap *simpHeap = (SimpleHeap *)hHeap;
|
2018-07-17 21:46:57 +03:00
|
|
|
|
|
|
|
if (simpHeap->maxSize && simpHeap->curSize + dwBytes > simpHeap->maxSize)
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
if (dwFlags == HEAP_ZERO_MEMORY)
|
|
|
|
ptr = calloc(1, dwBytes);
|
|
|
|
else
|
|
|
|
ptr = malloc(dwBytes);
|
|
|
|
|
|
|
|
simpHeap->allocs[ptr] = {ptr, dwBytes};
|
|
|
|
simpHeap->curSize += dwBytes;
|
|
|
|
|
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
LPVOID HeapReAlloc(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem, SIZE_T dwBytes) {
|
|
|
|
LPVOID ptr = nullptr;
|
2023-09-19 15:49:22 +03:00
|
|
|
SimpleHeap *simpHeap = (SimpleHeap *)hHeap;
|
2018-07-17 21:46:57 +03:00
|
|
|
SIZE_T oSize = simpHeap->allocs[lpMem].size;
|
|
|
|
|
2023-09-19 15:49:22 +03:00
|
|
|
if (simpHeap->maxSize &&
|
|
|
|
simpHeap->curSize - oSize + dwBytes > simpHeap->maxSize)
|
2018-07-17 21:46:57 +03:00
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
ptr = realloc(lpMem, dwBytes);
|
|
|
|
if (dwFlags == HEAP_ZERO_MEMORY && oSize < dwBytes)
|
2023-09-19 15:49:22 +03:00
|
|
|
memset((char *)ptr + oSize, 0, dwBytes - oSize);
|
2018-07-17 21:46:57 +03:00
|
|
|
|
|
|
|
simpHeap->allocs.erase(lpMem);
|
|
|
|
simpHeap->curSize -= oSize;
|
|
|
|
|
|
|
|
simpHeap->allocs[ptr] = {ptr, dwBytes};
|
|
|
|
simpHeap->curSize += dwBytes;
|
|
|
|
|
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL HeapFree(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem) {
|
2023-09-19 15:49:22 +03:00
|
|
|
SimpleHeap *simpHeap = (SimpleHeap *)hHeap;
|
2018-07-17 21:46:57 +03:00
|
|
|
SIZE_T oSize = simpHeap->allocs[lpMem].size;
|
|
|
|
|
|
|
|
free(lpMem);
|
|
|
|
|
|
|
|
simpHeap->allocs.erase(lpMem);
|
|
|
|
simpHeap->curSize -= oSize;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
SIZE_T HeapSize(HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem) {
|
2023-09-19 15:49:22 +03:00
|
|
|
SimpleHeap *simpHeap = (SimpleHeap *)hHeap;
|
2018-07-17 21:46:57 +03:00
|
|
|
return simpHeap->allocs[lpMem].size;
|
|
|
|
}
|
|
|
|
|
|
|
|
static SimpleHeap g_processHeap;
|
|
|
|
|
2023-09-19 15:49:22 +03:00
|
|
|
HANDLE GetProcessHeap() { return (HANDLE)&g_processHeap; }
|
2018-07-17 21:46:57 +03:00
|
|
|
|
2018-06-25 23:04:13 +03:00
|
|
|
#endif // _WIN32
|