mirror of
https://github.com/SoftEtherVPN/SoftEtherVPN.git
synced 2024-12-25 17:49:52 +03:00
Heap area protection of memory has been enhanced.
When memory is released and reallocated, a random security value called a canary is written to the before/after area of memory, and if the value has been modified, the process is terminated (restarted) for safety, assuming it is a buffer overflow of the memory area. This feature may effectively prevent confidentiality or integrity violations in the event that some heap area overflow vulnerability is discovered in this system in the future.
This commit is contained in:
parent
c49e462ed1
commit
2dec52b875
@ -2100,7 +2100,31 @@ void AbortExitEx(char *msg)
|
||||
f = fopen("abort_error_log.txt", "w");
|
||||
if (f != NULL)
|
||||
{
|
||||
SYSTEMTIME time = { 0 };
|
||||
char time_str[128] = { 0 };
|
||||
char *crlf = "\r\n";
|
||||
char *tag = "---------";
|
||||
|
||||
LocalTime(&time);
|
||||
|
||||
sprintf(time_str, "%04u-%02u-%02u %02u:%02u:%02u",
|
||||
time.wYear, time.wMonth, time.wDay,
|
||||
time.wHour, time.wMinute, time.wSecond);
|
||||
|
||||
fwrite(tag, 1, strlen(tag), f);
|
||||
|
||||
fwrite(crlf, 1, strlen(crlf), f);
|
||||
|
||||
fwrite(time_str, 1, strlen(time_str), f);
|
||||
|
||||
fwrite(crlf, 1, strlen(crlf), f);
|
||||
|
||||
fwrite(msg, 1, strlen(msg), f);
|
||||
|
||||
fwrite(crlf, 1, strlen(crlf), f);
|
||||
|
||||
fwrite(crlf, 1, strlen(crlf), f);
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
|
@ -282,7 +282,8 @@ typedef struct TRACKING_LIST TRACKING_LIST;
|
||||
typedef struct IO IO;
|
||||
|
||||
// Memory.h
|
||||
typedef struct MEMTAG MEMTAG;
|
||||
typedef struct MEMTAG1 MEMTAG1;
|
||||
typedef struct MEMTAG2 MEMTAG2;
|
||||
typedef struct BUF BUF;
|
||||
typedef struct FIFO FIFO;
|
||||
typedef struct LIST LIST;
|
||||
|
@ -65,6 +65,8 @@ void InitProcessCallOnce()
|
||||
{
|
||||
init_proc_once_flag = true;
|
||||
|
||||
InitCanaryRand();
|
||||
|
||||
#ifdef OS_WIN32
|
||||
MsInitProcessCallOnce();
|
||||
#endif // OS_WIN32
|
||||
|
@ -16,10 +16,16 @@
|
||||
#include "Object.h"
|
||||
#include "OS.h"
|
||||
#include "Str.h"
|
||||
#include "Tick64.h"
|
||||
#include "Tracking.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifdef OS_UNIX
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
@ -34,6 +40,105 @@
|
||||
|
||||
static UINT fifo_current_realloc_mem_size = FIFO_REALLOC_MEM_SIZE;
|
||||
|
||||
static bool canary_inited = false;
|
||||
typedef struct CANARY_RAND_DATA
|
||||
{
|
||||
UCHAR Data[CANARY_RAND_SIZE + 4];
|
||||
} CANARY_RAND_DATA;
|
||||
|
||||
static CANARY_RAND_DATA canary_rand_data[NUM_CANARY_RAND] = { 0 };
|
||||
|
||||
static UINT64 canary_memtag_magic1 = 0;
|
||||
static UINT64 canary_memtag_magic2 = 0;
|
||||
|
||||
UCHAR *GetCanaryRand(UINT id)
|
||||
{
|
||||
if (id >= NUM_CANARY_RAND)
|
||||
{
|
||||
id = NUM_CANARY_RAND - 1;
|
||||
}
|
||||
|
||||
return &((canary_rand_data[id].Data)[0]);
|
||||
}
|
||||
|
||||
void InitCanaryRand()
|
||||
{
|
||||
SYSTEMTIME st = { 0 };
|
||||
char random_seed[1024] = { 0 };
|
||||
UINT64 t1 = 0, t2 = 0;
|
||||
if (canary_inited)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef OS_WIN32
|
||||
Win32GetSystemTime(&st);
|
||||
memcpy(&t1, ((UCHAR *)&st) + 0, 8);
|
||||
memcpy(&t2, ((UCHAR *)&st) + 8, 8);
|
||||
#else // OS_WIN32
|
||||
struct timeval tv = { 0 };
|
||||
struct timezone tz = { 0 };
|
||||
gettimeofday(&tv, &tz);
|
||||
t1 = (UINT64)tv.tv_sec;
|
||||
t2 = (UINT64)tv.tv_usec;
|
||||
#endif // OS_WIN32
|
||||
|
||||
{
|
||||
UINT64 dos_rand = (UINT64)rand();
|
||||
UINT64 tick1 = TickHighresNano64(true);
|
||||
UINT64 tick2 = TickHighresNano64(true);
|
||||
|
||||
UINT i;
|
||||
|
||||
void *p1 = malloc(1);
|
||||
void *p2 = malloc(1);
|
||||
|
||||
for (i = 0;i < NUM_CANARY_RAND;i++)
|
||||
{
|
||||
// using sprintf() here is safe.
|
||||
sprintf(random_seed,
|
||||
"%u "
|
||||
"%llu "
|
||||
"%llu "
|
||||
"%llu "
|
||||
"%llu "
|
||||
"%llu "
|
||||
"%llu "
|
||||
"%llu "
|
||||
"%llu "
|
||||
"%llu "
|
||||
"%llu "
|
||||
"%llu "
|
||||
"%u "
|
||||
,
|
||||
i,
|
||||
(UINT64)InitCanaryRand,
|
||||
(UINT64)&canary_inited,
|
||||
(UINT64) & ((canary_rand_data[0].Data)[0]),
|
||||
(UINT64)&random_seed[0],
|
||||
tick1,
|
||||
tick2,
|
||||
dos_rand,
|
||||
(UINT64)p1,
|
||||
(UINT64)p2,
|
||||
t1,
|
||||
t2,
|
||||
~i
|
||||
);
|
||||
|
||||
Sha0(canary_rand_data[i].Data, random_seed, (UINT)strlen(random_seed));
|
||||
}
|
||||
|
||||
free(p1);
|
||||
free(p2);
|
||||
|
||||
canary_memtag_magic1 = *((UINT64 *)(GetCanaryRand(CANARY_RAND_ID_MEMTAG_MAGIC) + 0));
|
||||
canary_memtag_magic2 = *((UINT64 *)(GetCanaryRand(CANARY_RAND_ID_MEMTAG_MAGIC) + 8));
|
||||
|
||||
canary_inited = true;
|
||||
}
|
||||
}
|
||||
|
||||
// New PRand
|
||||
PRAND *NewPRand(void *key, UINT key_size)
|
||||
{
|
||||
@ -3519,33 +3624,52 @@ void *Malloc(UINT size)
|
||||
}
|
||||
void *MallocEx(UINT size, bool zero_clear_when_free)
|
||||
{
|
||||
MEMTAG *tag;
|
||||
MEMTAG1 *tag1;
|
||||
MEMTAG2 *tag2;
|
||||
UINT real_size;
|
||||
|
||||
if (canary_inited == false)
|
||||
{
|
||||
InitCanaryRand();
|
||||
}
|
||||
|
||||
if (size > MAX_MALLOC_MEM_SIZE)
|
||||
{
|
||||
AbortExitEx("MallocEx() error: too large size");
|
||||
}
|
||||
|
||||
real_size = CALC_MALLOCSIZE(size);
|
||||
|
||||
tag = InternalMalloc(real_size);
|
||||
tag1 = InternalMalloc(real_size);
|
||||
|
||||
Zero(tag, sizeof(MEMTAG));
|
||||
tag->Magic = MEMTAG_MAGIC;
|
||||
tag->Size = size;
|
||||
tag->ZeroFree = zero_clear_when_free;
|
||||
tag1->Magic = canary_memtag_magic1 ^ ((UINT64)tag1 * GOLDEN_RATION_PRIME_U64);
|
||||
tag1->Size = size;
|
||||
tag1->ZeroFree = zero_clear_when_free;
|
||||
|
||||
return MEMTAG_TO_POINTER(tag);
|
||||
tag2 = (MEMTAG2 *)(((UCHAR *)tag1) + CALC_MALLOCSIZE(tag1->Size) - sizeof(MEMTAG2));
|
||||
tag2->Magic = canary_memtag_magic2 ^ ((UINT64)tag2 * GOLDEN_RATION_PRIME_U64);
|
||||
|
||||
return MEMTAG1_TO_POINTER(tag1);
|
||||
}
|
||||
|
||||
// Get memory size
|
||||
UINT GetMemSize(void *addr)
|
||||
{
|
||||
MEMTAG *tag;
|
||||
MEMTAG1 *tag;
|
||||
|
||||
if (canary_inited == false)
|
||||
{
|
||||
InitCanaryRand();
|
||||
}
|
||||
|
||||
// Validate arguments
|
||||
if (IS_NULL_POINTER(addr))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
tag = POINTER_TO_MEMTAG(addr);
|
||||
CheckMemTag(tag);
|
||||
tag = POINTER_TO_MEMTAG1(addr);
|
||||
CheckMemTag1(tag);
|
||||
|
||||
return tag->Size;
|
||||
}
|
||||
@ -3553,20 +3677,35 @@ UINT GetMemSize(void *addr)
|
||||
// ReAlloc
|
||||
void *ReAlloc(void *addr, UINT size)
|
||||
{
|
||||
MEMTAG *tag;
|
||||
MEMTAG1 *tag1;
|
||||
MEMTAG2 *tag2;
|
||||
bool zerofree;
|
||||
|
||||
if (canary_inited == false)
|
||||
{
|
||||
InitCanaryRand();
|
||||
}
|
||||
|
||||
if (size > MAX_MALLOC_MEM_SIZE)
|
||||
{
|
||||
AbortExitEx("ReAlloc() error: too large size");
|
||||
}
|
||||
|
||||
// Validate arguments
|
||||
if (IS_NULL_POINTER(addr))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tag = POINTER_TO_MEMTAG(addr);
|
||||
CheckMemTag(tag);
|
||||
tag1 = POINTER_TO_MEMTAG1(addr);
|
||||
CheckMemTag1(tag1);
|
||||
|
||||
zerofree = tag->ZeroFree;
|
||||
tag2 = (MEMTAG2 *)(((UCHAR *)tag1) + CALC_MALLOCSIZE(tag1->Size) - sizeof(MEMTAG2));
|
||||
CheckMemTag2(tag2);
|
||||
|
||||
if (tag->Size == size)
|
||||
zerofree = tag1->ZeroFree;
|
||||
|
||||
if (tag1->Size == size)
|
||||
{
|
||||
// No size change
|
||||
return addr;
|
||||
@ -3578,10 +3717,10 @@ void *ReAlloc(void *addr, UINT size)
|
||||
// Size changed (zero clearing required)
|
||||
void *new_p = MallocEx(size, true);
|
||||
|
||||
if (tag->Size <= size)
|
||||
if (tag1->Size <= size)
|
||||
{
|
||||
// Size expansion
|
||||
Copy(new_p, addr, tag->Size);
|
||||
Copy(new_p, addr, tag1->Size);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -3597,13 +3736,22 @@ void *ReAlloc(void *addr, UINT size)
|
||||
else
|
||||
{
|
||||
// Size changed
|
||||
MEMTAG *tag2 = InternalReAlloc(tag, CALC_MALLOCSIZE(size));
|
||||
MEMTAG1 *tag1_new;
|
||||
MEMTAG2 *tag2_new;
|
||||
|
||||
Zero(tag2, sizeof(MEMTAG));
|
||||
tag2->Magic = MEMTAG_MAGIC;
|
||||
tag2->Size = size;
|
||||
tag1->Magic = 0;
|
||||
tag2->Magic = 0;
|
||||
|
||||
return MEMTAG_TO_POINTER(tag2);
|
||||
tag1_new = InternalReAlloc(tag1, CALC_MALLOCSIZE(size));
|
||||
|
||||
tag1_new->Magic = canary_memtag_magic1 ^ ((UINT64)tag1_new * GOLDEN_RATION_PRIME_U64);
|
||||
tag1_new->Size = size;
|
||||
tag1_new->ZeroFree = 0;
|
||||
|
||||
tag2_new = (MEMTAG2 *)(((UCHAR *)tag1_new) + CALC_MALLOCSIZE(size) - sizeof(MEMTAG2));
|
||||
tag2_new->Magic = canary_memtag_magic2 ^ ((UINT64)tag2_new * GOLDEN_RATION_PRIME_U64);
|
||||
|
||||
return MEMTAG1_TO_POINTER(tag1_new);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3611,25 +3759,35 @@ void *ReAlloc(void *addr, UINT size)
|
||||
// Free
|
||||
void Free(void *addr)
|
||||
{
|
||||
MEMTAG *tag;
|
||||
MEMTAG1 *tag1;
|
||||
MEMTAG2 *tag2;
|
||||
// Validate arguments
|
||||
if (IS_NULL_POINTER(addr))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
tag = POINTER_TO_MEMTAG(addr);
|
||||
CheckMemTag(tag);
|
||||
if (canary_inited == false)
|
||||
{
|
||||
InitCanaryRand();
|
||||
}
|
||||
|
||||
if (tag->ZeroFree)
|
||||
tag1 = POINTER_TO_MEMTAG1(addr);
|
||||
CheckMemTag1(tag1);
|
||||
|
||||
tag2 = (MEMTAG2 *)(((UCHAR *)tag1) + CALC_MALLOCSIZE(tag1->Size) - sizeof(MEMTAG2));
|
||||
CheckMemTag2(tag2);
|
||||
|
||||
if (tag1->ZeroFree)
|
||||
{
|
||||
// Zero clear
|
||||
Zero(addr, tag->Size);
|
||||
Zero(addr, tag1->Size);
|
||||
}
|
||||
|
||||
// Memory release
|
||||
tag->Magic = 0;
|
||||
InternalFree(tag);
|
||||
tag1->Magic = 0;
|
||||
tag2->Magic = 0;
|
||||
InternalFree(tag1);
|
||||
}
|
||||
|
||||
// Free and set pointer's value to NULL
|
||||
@ -3639,24 +3797,36 @@ void FreeSafe(void **addr)
|
||||
*addr = NULL;
|
||||
}
|
||||
|
||||
// Check the memtag
|
||||
void CheckMemTag(MEMTAG *tag)
|
||||
// Check the memtag1
|
||||
void CheckMemTag1(MEMTAG1 *tag)
|
||||
{
|
||||
if (IsTrackingEnabled() == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate arguments
|
||||
if (tag == NULL)
|
||||
{
|
||||
AbortExitEx("CheckMemTag: tag == NULL");
|
||||
AbortExitEx("CheckMemTag1: tag1 == NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
if (tag->Magic != MEMTAG_MAGIC)
|
||||
if (tag->Magic != (canary_memtag_magic1 ^ ((UINT64)tag * GOLDEN_RATION_PRIME_U64)))
|
||||
{
|
||||
AbortExitEx("CheckMemTag: tag->Magic != MEMTAG_MAGIC");
|
||||
AbortExitEx("CheckMemTag1: tag1->Magic != canary_memtag_magic1");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check the memtag2
|
||||
void CheckMemTag2(MEMTAG2 *tag)
|
||||
{
|
||||
// Validate arguments
|
||||
if (tag == NULL)
|
||||
{
|
||||
AbortExitEx("CheckMemTag2: tag2 == NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
if (tag->Magic != (canary_memtag_magic2 ^ ((UINT64)tag * GOLDEN_RATION_PRIME_U64)))
|
||||
{
|
||||
AbortExitEx("CheckMemTag2: tag2->Magic != canary_memtag_magic2");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -14,29 +14,38 @@
|
||||
#define MallocFast Malloc
|
||||
#define ZeroMallocFast ZeroMalloc
|
||||
|
||||
#define MAX_MALLOC_MEM_SIZE (0xffffffff - 64)
|
||||
|
||||
// Memory size that can be passed to the kernel at a time
|
||||
#define MAX_SEND_BUF_MEM_SIZE (10 * 1024 * 1024)
|
||||
|
||||
// The magic number for memory tag
|
||||
#define MEMTAG_MAGIC 0x49414449
|
||||
|
||||
#define CALC_MALLOCSIZE(size) ((MAX(size, 1)) + sizeof(MEMTAG))
|
||||
#define MEMTAG_TO_POINTER(p) ((void *)(((UCHAR *)(p)) + sizeof(MEMTAG)))
|
||||
#define POINTER_TO_MEMTAG(p) ((MEMTAG *)(((UCHAR *)(p)) - sizeof(MEMTAG)))
|
||||
#define IS_NULL_POINTER(p) (((p) == NULL) || ((POINTER_TO_UINT64(p) == (UINT64)sizeof(MEMTAG))))
|
||||
#define CALC_MALLOCSIZE(size) (((MAX(size, 1) + 7) / 8) * 8 + sizeof(MEMTAG1) + sizeof(MEMTAG2))
|
||||
#define MEMTAG1_TO_POINTER(p) ((void *)(((UCHAR *)(p)) + sizeof(MEMTAG1)))
|
||||
#define POINTER_TO_MEMTAG1(p) ((MEMTAG1 *)(((UCHAR *)(p)) - sizeof(MEMTAG1)))
|
||||
#define IS_NULL_POINTER(p) (((p) == NULL) || ((POINTER_TO_UINT64(p) == (UINT64)sizeof(MEMTAG1))))
|
||||
#define PTR_TO_PTR(p) ((void **)(&p))
|
||||
|
||||
// Golden Ratio Prime
|
||||
// From https://github.com/torvalds/linux/blob/88c5083442454e5e8a505b11fa16f32d2879651e/include/linux/hash.h
|
||||
#define GOLDEN_RATION_PRIME_U32 ((UINT32)0x61C88647)
|
||||
#define GOLDEN_RATION_PRIME_U64 ((UINT64)7046029254386353131ULL) // 0x61C8864680B583EB
|
||||
|
||||
// Fixed size of a block of memory pool
|
||||
#define MEMPOOL_MAX_SIZE 3000
|
||||
|
||||
|
||||
// Memory tag
|
||||
struct MEMTAG
|
||||
// Memory tag 1
|
||||
struct MEMTAG1
|
||||
{
|
||||
UINT Magic;
|
||||
UINT64 Magic;
|
||||
UINT Size;
|
||||
bool ZeroFree;
|
||||
UINT Padding;
|
||||
};
|
||||
|
||||
// Memory tag 2
|
||||
struct MEMTAG2
|
||||
{
|
||||
UINT64 Magic;
|
||||
};
|
||||
|
||||
// Buffer
|
||||
@ -174,7 +183,8 @@ void *ZeroMallocEx(UINT size, bool zero_clear_when_free);
|
||||
void *ReAlloc(void *addr, UINT size);
|
||||
void Free(void *addr);
|
||||
void FreeSafe(void **addr);
|
||||
void CheckMemTag(MEMTAG *tag);
|
||||
void CheckMemTag1(MEMTAG1 *tag);
|
||||
void CheckMemTag2(MEMTAG2 *tag);
|
||||
UINT GetMemSize(void *addr);
|
||||
|
||||
void *InternalMalloc(UINT size);
|
||||
@ -364,5 +374,12 @@ LIST *NewStrList();
|
||||
void ReleaseStrList(LIST *o);
|
||||
bool AddStrToStrListDistinct(LIST *o, char *str);
|
||||
|
||||
#define NUM_CANARY_RAND 32
|
||||
#define CANARY_RAND_ID_MEMTAG_MAGIC 0
|
||||
#define CANARY_RAND_SIZE 20
|
||||
|
||||
void InitCanaryRand();
|
||||
UCHAR *GetCanaryRand(UINT id);
|
||||
|
||||
#endif // MEMORY_H
|
||||
|
||||
|
@ -34,6 +34,23 @@ UINT64 TickHighres64()
|
||||
|
||||
}
|
||||
|
||||
UINT64 TickHighresNano64(bool raw)
|
||||
{
|
||||
UINT64 ret = 0;
|
||||
|
||||
#ifdef OS_WIN32
|
||||
|
||||
ret = (UINT64)(MsGetHiResTimeSpan(MsGetHiResCounter()) * 1000000000.0f);
|
||||
|
||||
#else // OS_WIN32
|
||||
|
||||
ret = UnixGetHighresTickNano64(raw);
|
||||
|
||||
#endif // OS_WIN32
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Convert the Tick value to time
|
||||
UINT64 Tick64ToTime64(UINT64 tick)
|
||||
{
|
||||
|
@ -49,6 +49,7 @@ UINT64 Diff64(UINT64 a, UINT64 b);
|
||||
UINT64 Tick64ToTime64(UINT64 tick);
|
||||
UINT64 TickToTime(UINT64 tick);
|
||||
UINT64 TickHighres64();
|
||||
UINT64 TickHighresNano64(bool raw);
|
||||
|
||||
#endif // TICK64_H
|
||||
|
||||
|
@ -2008,6 +2008,68 @@ void UnixGetSystemTime(SYSTEMTIME *system_time)
|
||||
pthread_mutex_unlock(&get_time_lock);
|
||||
}
|
||||
|
||||
UINT64 UnixGetHighresTickNano64(bool raw)
|
||||
{
|
||||
#if defined(OS_WIN32) || defined(CLOCK_REALTIME) || defined(CLOCK_MONOTONIC) || defined(CLOCK_HIGHRES)
|
||||
struct timespec t;
|
||||
UINT64 ret;
|
||||
static bool akirame = false;
|
||||
|
||||
if (akirame)
|
||||
{
|
||||
return UnixGetTick64() * 1000000ULL;
|
||||
}
|
||||
|
||||
Zero(&t, sizeof(t));
|
||||
|
||||
if (raw == false)
|
||||
{
|
||||
// Function to get the boot time of the system
|
||||
// Be careful. The Implementation is depend on the system.
|
||||
#ifdef CLOCK_HIGHRES
|
||||
clock_gettime(CLOCK_HIGHRES, &t);
|
||||
#else // CLOCK_HIGHRES
|
||||
#ifdef CLOCK_MONOTONIC
|
||||
clock_gettime(CLOCK_MONOTONIC, &t);
|
||||
#else // CLOCK_MONOTONIC
|
||||
clock_gettime(CLOCK_REALTIME, &t);
|
||||
#endif // CLOCK_MONOTONIC
|
||||
#endif // CLOCK_HIGHRES
|
||||
}
|
||||
else
|
||||
{
|
||||
// Function to get the boot time of the system
|
||||
// Be careful. The Implementation is depend on the system.
|
||||
#ifdef CLOCK_HIGHRES
|
||||
clock_gettime(CLOCK_HIGHRES, &t);
|
||||
#else // CLOCK_HIGHRES
|
||||
#ifdef CLOCK_MONOTONIC_RAW
|
||||
clock_gettime(CLOCK_MONOTONIC_RAW, &t);
|
||||
#else // CLOCK_MONOTONIC_RAW
|
||||
#ifdef CLOCK_MONOTONIC
|
||||
clock_gettime(CLOCK_MONOTONIC, &t);
|
||||
#else // CLOCK_MONOTONIC
|
||||
clock_gettime(CLOCK_REALTIME, &t);
|
||||
#endif // CLOCK_MONOTONIC
|
||||
#endif // CLOCK_MONOTONIC_RAW
|
||||
#endif // CLOCK_HIGHRES
|
||||
}
|
||||
|
||||
ret = ((UINT64)((UINT)t.tv_sec)) * 1000000000LL + (UINT64)t.tv_nsec;
|
||||
|
||||
if (akirame == false && ret == 0)
|
||||
{
|
||||
ret = UnixGetTick64() * 1000000ULL;
|
||||
akirame = true;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
#else
|
||||
return UnixGetTick64() * 1000000ULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Get the system timer (64bit)
|
||||
UINT64 UnixGetTick64()
|
||||
{
|
||||
|
@ -117,6 +117,7 @@ void UnixSetThreadPriorityRealtime();
|
||||
void UnixSetResourceLimit(UINT id, UINT64 value);
|
||||
bool UnixIs64BitRlimSupported();
|
||||
UINT64 UnixGetTick64();
|
||||
UINT64 UnixGetHighresTickNano64(bool raw);
|
||||
void UnixSigChldHandler(int sig);
|
||||
void UnixCloseIO();
|
||||
void UnixGetCurrentDir(char *dir, UINT size);
|
||||
|
Loading…
Reference in New Issue
Block a user