1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-10 09:58:01 +00:00
putty-source/windows/winmiscs.c
Simon Tatham 5d718ef64b Whitespace rationalisation of entire code base.
The number of people has been steadily increasing who read our source
code with an editor that thinks tab stops are 4 spaces apart, as
opposed to the traditional tty-derived 8 that the PuTTY code expects.

So I've been wondering for ages about just fixing it, and switching to
a spaces-only policy throughout the code. And I recently found out
about 'git blame -w', which should make this change not too disruptive
for the purposes of source-control archaeology; so perhaps now is the
time.

While I'm at it, I've also taken the opportunity to remove all the
trailing spaces from source lines (on the basis that git dislikes
them, and is the only thing that seems to have a strong opinion one
way or the other).
    
Apologies to anyone downstream of this code who has complicated patch
sets to rebase past this change. I don't intend it to be needed again.
2019-09-08 20:29:21 +01:00

278 lines
6.9 KiB
C

/*
* winmiscs.c: Windows-specific standalone functions. Has the same
* relationship to winmisc.c that utils.c does to misc.c, but the
* corresponding name 'winutils.c' was already taken.
*/
#include "putty.h"
#ifndef NO_SECUREZEROMEMORY
/*
* Windows implementation of smemclr (see misc.c) using SecureZeroMemory.
*/
void smemclr(void *b, size_t n) {
if (b && n > 0)
SecureZeroMemory(b, n);
}
#endif
#ifdef MINEFIELD
/*
* Minefield - a Windows equivalent for Electric Fence
*/
#define PAGESIZE 4096
/*
* Design:
*
* We start by reserving as much virtual address space as Windows
* will sensibly (or not sensibly) let us have. We flag it all as
* invalid memory.
*
* Any allocation attempt is satisfied by committing one or more
* pages, with an uncommitted page on either side. The returned
* memory region is jammed up against the _end_ of the pages.
*
* Freeing anything causes instantaneous decommitment of the pages
* involved, so stale pointers are caught as soon as possible.
*/
static int minefield_initialised = 0;
static void *minefield_region = NULL;
static long minefield_size = 0;
static long minefield_npages = 0;
static long minefield_curpos = 0;
static unsigned short *minefield_admin = NULL;
static void *minefield_pages = NULL;
static void minefield_admin_hide(int hide)
{
int access = hide ? PAGE_NOACCESS : PAGE_READWRITE;
VirtualProtect(minefield_admin, minefield_npages * 2, access, NULL);
}
static void minefield_init(void)
{
int size;
int admin_size;
int i;
for (size = 0x40000000; size > 0; size = ((size >> 3) * 7) & ~0xFFF) {
minefield_region = VirtualAlloc(NULL, size,
MEM_RESERVE, PAGE_NOACCESS);
if (minefield_region)
break;
}
minefield_size = size;
/*
* Firstly, allocate a section of that to be the admin block.
* We'll need a two-byte field for each page.
*/
minefield_admin = minefield_region;
minefield_npages = minefield_size / PAGESIZE;
admin_size = (minefield_npages * 2 + PAGESIZE - 1) & ~(PAGESIZE - 1);
minefield_npages = (minefield_size - admin_size) / PAGESIZE;
minefield_pages = (char *) minefield_region + admin_size;
/*
* Commit the admin region.
*/
VirtualAlloc(minefield_admin, minefield_npages * 2,
MEM_COMMIT, PAGE_READWRITE);
/*
* Mark all pages as unused (0xFFFF).
*/
for (i = 0; i < minefield_npages; i++)
minefield_admin[i] = 0xFFFF;
/*
* Hide the admin region.
*/
minefield_admin_hide(1);
minefield_initialised = 1;
}
static void minefield_bomb(void)
{
div(1, *(int *) minefield_pages);
}
static void *minefield_alloc(int size)
{
int npages;
int pos, lim, region_end, region_start;
int start;
int i;
npages = (size + PAGESIZE - 1) / PAGESIZE;
minefield_admin_hide(0);
/*
* Search from current position until we find a contiguous
* bunch of npages+2 unused pages.
*/
pos = minefield_curpos;
lim = minefield_npages;
while (1) {
/* Skip over used pages. */
while (pos < lim && minefield_admin[pos] != 0xFFFF)
pos++;
/* Count unused pages. */
start = pos;
while (pos < lim && pos - start < npages + 2 &&
minefield_admin[pos] == 0xFFFF)
pos++;
if (pos - start == npages + 2)
break;
/* If we've reached the limit, reset the limit or stop. */
if (pos >= lim) {
if (lim == minefield_npages) {
/* go round and start again at zero */
lim = minefield_curpos;
pos = 0;
} else {
minefield_admin_hide(1);
return NULL;
}
}
}
minefield_curpos = pos - 1;
/*
* We have npages+2 unused pages starting at start. We leave
* the first and last of these alone and use the rest.
*/
region_end = (start + npages + 1) * PAGESIZE;
region_start = region_end - size;
/* FIXME: could align here if we wanted */
/*
* Update the admin region.
*/
for (i = start + 2; i < start + npages + 1; i++)
minefield_admin[i] = 0xFFFE; /* used but no region starts here */
minefield_admin[start + 1] = region_start % PAGESIZE;
minefield_admin_hide(1);
VirtualAlloc((char *) minefield_pages + region_start, size,
MEM_COMMIT, PAGE_READWRITE);
return (char *) minefield_pages + region_start;
}
static void minefield_free(void *ptr)
{
int region_start, i, j;
minefield_admin_hide(0);
region_start = (char *) ptr - (char *) minefield_pages;
i = region_start / PAGESIZE;
if (i < 0 || i >= minefield_npages ||
minefield_admin[i] != region_start % PAGESIZE)
minefield_bomb();
for (j = i; j < minefield_npages && minefield_admin[j] != 0xFFFF; j++) {
minefield_admin[j] = 0xFFFF;
}
VirtualFree(ptr, j * PAGESIZE - region_start, MEM_DECOMMIT);
minefield_admin_hide(1);
}
static int minefield_get_size(void *ptr)
{
int region_start, i, j;
minefield_admin_hide(0);
region_start = (char *) ptr - (char *) minefield_pages;
i = region_start / PAGESIZE;
if (i < 0 || i >= minefield_npages ||
minefield_admin[i] != region_start % PAGESIZE)
minefield_bomb();
for (j = i; j < minefield_npages && minefield_admin[j] != 0xFFFF; j++);
minefield_admin_hide(1);
return j * PAGESIZE - region_start;
}
void *minefield_c_malloc(size_t size)
{
if (!minefield_initialised)
minefield_init();
return minefield_alloc(size);
}
void minefield_c_free(void *p)
{
if (!minefield_initialised)
minefield_init();
minefield_free(p);
}
/*
* realloc _always_ moves the chunk, for rapid detection of code
* that assumes it won't.
*/
void *minefield_c_realloc(void *p, size_t size)
{
size_t oldsize;
void *q;
if (!minefield_initialised)
minefield_init();
q = minefield_alloc(size);
oldsize = minefield_get_size(p);
memcpy(q, p, (oldsize < size ? oldsize : size));
minefield_free(p);
return q;
}
#endif /* MINEFIELD */
#if defined _MSC_VER && _MSC_VER < 1800
/*
* Work around lack of strtoumax in older MSVC libraries
*/
uintmax_t strtoumax(const char *nptr, char **endptr, int base)
{
return _strtoui64(nptr, endptr, base);
}
#endif
#if defined _M_ARM || defined _M_ARM64
bool platform_aes_hw_available(void)
{
return IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE);
}
bool platform_sha256_hw_available(void)
{
return IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE);
}
bool platform_sha1_hw_available(void)
{
return IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE);
}
#endif
bool is_console_handle(HANDLE handle)
{
DWORD ignored_output;
if (GetConsoleMode(handle, &ignored_output))
return true;
return false;
}