diff --git a/src/Mayaqua/Kernel.c b/src/Mayaqua/Kernel.c index 99890a08..ec4621f7 100644 --- a/src/Mayaqua/Kernel.c +++ b/src/Mayaqua/Kernel.c @@ -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); } diff --git a/src/Mayaqua/MayaType.h b/src/Mayaqua/MayaType.h index efdfaa59..483fedad 100644 --- a/src/Mayaqua/MayaType.h +++ b/src/Mayaqua/MayaType.h @@ -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; diff --git a/src/Mayaqua/Mayaqua.c b/src/Mayaqua/Mayaqua.c index 88f03684..86492751 100644 --- a/src/Mayaqua/Mayaqua.c +++ b/src/Mayaqua/Mayaqua.c @@ -65,6 +65,8 @@ void InitProcessCallOnce() { init_proc_once_flag = true; + InitCanaryRand(); + #ifdef OS_WIN32 MsInitProcessCallOnce(); #endif // OS_WIN32 diff --git a/src/Mayaqua/Memory.c b/src/Mayaqua/Memory.c index aa793d70..67929483 100644 --- a/src/Mayaqua/Memory.c +++ b/src/Mayaqua/Memory.c @@ -16,10 +16,16 @@ #include "Object.h" #include "OS.h" #include "Str.h" +#include "Tick64.h" #include "Tracking.h" #include #include +#include + +#ifdef OS_UNIX +#include +#endif #include @@ -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; } } diff --git a/src/Mayaqua/Memory.h b/src/Mayaqua/Memory.h index 8b39cd9d..cb94a06d 100644 --- a/src/Mayaqua/Memory.h +++ b/src/Mayaqua/Memory.h @@ -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 diff --git a/src/Mayaqua/Tick64.c b/src/Mayaqua/Tick64.c index f99a623f..02932677 100644 --- a/src/Mayaqua/Tick64.c +++ b/src/Mayaqua/Tick64.c @@ -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) { diff --git a/src/Mayaqua/Tick64.h b/src/Mayaqua/Tick64.h index 1791c517..bde8517d 100644 --- a/src/Mayaqua/Tick64.h +++ b/src/Mayaqua/Tick64.h @@ -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 diff --git a/src/Mayaqua/Unix.c b/src/Mayaqua/Unix.c index bd1263c9..0c3778df 100755 --- a/src/Mayaqua/Unix.c +++ b/src/Mayaqua/Unix.c @@ -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() { diff --git a/src/Mayaqua/Unix.h b/src/Mayaqua/Unix.h index e382d686..9777564f 100644 --- a/src/Mayaqua/Unix.h +++ b/src/Mayaqua/Unix.h @@ -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);