feat(libc): operator new/delete, bounds-checked functions, char locale facets and runtime helpers
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ButHENCbXXt8h4EZuWUabJ
This commit is contained in:
parent
7656458121
commit
a599eca727
|
|
@ -1,7 +1,14 @@
|
|||
#include "prx/libc/include/General.hpp"
|
||||
#include "prx/libc/include/HeapDiagnostics.hpp"
|
||||
|
||||
extern "C" {
|
||||
|
||||
int Need_sceLibcInternal_nid_postfix = 1;
|
||||
|
||||
void APS5_VABI __cxa_finalize_nid_postfix(void* dsoHandle) {
|
||||
CxaFinalize_nid_no_patch(dsoHandle);
|
||||
}
|
||||
|
||||
void APS5_VABI sceLibcHeapGetTraceInfo_nid_postfix(Info* info) {
|
||||
LibcHeapTraceInfo_nid_no_patch(info);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include "general/ExportMacros.hpp"
|
||||
|
||||
extern "C" void NotImplemented_nid_no_patch(const char* funcName);
|
||||
extern "C" void CxaFinalize_nid_no_patch(void* dsoHandle);
|
||||
|
||||
extern "C" std::filesystem::path ResolvePath_nid_no_patch(const char* path);
|
||||
// Guest path aliases: a guest prefix such as "/_sm/0" (a save-data mount point) resolves to a host
|
||||
|
|
|
|||
|
|
@ -9,4 +9,12 @@ inline unsigned int GccAtomicFetchSub(volatile unsigned int* target, unsigned in
|
|||
return __atomic_fetch_sub(target, value, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
|
||||
inline bool GccAtomicCompareExchangeWeak(volatile unsigned int* target, unsigned int* expected, unsigned int desired) {
|
||||
return __atomic_compare_exchange_n(target, expected, desired, true, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
|
||||
inline unsigned int GccAtomicLoad(volatile unsigned int* target) {
|
||||
return __atomic_load_n(target, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -63,6 +63,14 @@ FileStream* APS5_VABI fopen_nid_postfix(const char* filename, const char* mode)
|
|||
return stream.release();
|
||||
}
|
||||
|
||||
int APS5_VABI fopen_s_nid_postfix(FileStream** result, const char* filename, const char* mode) {
|
||||
constexpr int GuestEinval = 22;
|
||||
constexpr int GuestEnoent = 2;
|
||||
if (!result || !filename || !mode) return GuestEinval;
|
||||
*result = fopen_nid_postfix(filename, mode);
|
||||
return *result ? 0 : GuestEnoent;
|
||||
}
|
||||
|
||||
int APS5_VABI fclose_nid_postfix(FileStream* stream) {
|
||||
GetNativeStream(stream);
|
||||
std::unique_ptr<FileStream> owner(stream->IsDynamic() ? stream : nullptr);
|
||||
|
|
@ -121,6 +129,17 @@ int APS5_VABI fseek_nid_postfix(FileStream* stream, std::int64_t offset, int ori
|
|||
|
||||
std::int64_t APS5_VABI ftell_nid_postfix(FileStream* stream) { return ftello_nid_postfix(stream); }
|
||||
|
||||
int APS5_VABI fgetpos_nid_postfix(FileStream* stream, std::int64_t* position) {
|
||||
if (!position) throw std::invalid_argument("fgetpos: null position");
|
||||
*position = ftello_nid_postfix(stream);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI fsetpos_nid_postfix(FileStream* stream, const std::int64_t* position) {
|
||||
if (!position) throw std::invalid_argument("fsetpos: null position");
|
||||
return fseeko_nid_postfix(stream, *position, SEEK_SET);
|
||||
}
|
||||
|
||||
int APS5_VABI fputs_nid_postfix(const char* str, FileStream* stream) {
|
||||
if (!str) throw std::runtime_error("fputs: null string");
|
||||
const int result = std::fputs(str, GetNativeStream(stream));
|
||||
|
|
@ -149,6 +168,15 @@ void* APS5_VABI memalign_nid_postfix(size_t alignment, size_t size) {
|
|||
return ApplicationHeapAlign_nid_no_patch(alignment, size);
|
||||
}
|
||||
|
||||
void* APS5_VABI aligned_alloc_nid_postfix(size_t alignment, size_t size) {
|
||||
return ApplicationHeapAlign_nid_no_patch(alignment, size);
|
||||
}
|
||||
|
||||
void* APS5_VABI reallocalign_nid_postfix(void* ptr, size_t size, size_t alignment) {
|
||||
if (ptr != nullptr) NotImplemented_nid_no_patch("reallocalign of an existing block");
|
||||
return ApplicationHeapAlign_nid_no_patch(alignment, size);
|
||||
}
|
||||
|
||||
void* APS5_VABI calloc_nid_postfix(size_t count, size_t size) {
|
||||
return ApplicationHeapCalloc_nid_no_patch(count, size);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -169,6 +169,56 @@ int APS5_VABI vsnprintf_nid_postfix(char* str, size_t size, const char* format,
|
|||
#endif
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
int APS5_VABI snprintf_s_nid_postfix(char* buffer, size_t size, const char* format, ...) {
|
||||
__builtin_sysv_va_list args;
|
||||
__builtin_sysv_va_start(args, format);
|
||||
const int result = LibcDetail::FormatWindows(buffer, size, format, args);
|
||||
__builtin_sysv_va_end(args);
|
||||
return result;
|
||||
}
|
||||
|
||||
int APS5_VABI printf_s_nid_postfix(const char* format, ...) {
|
||||
__builtin_sysv_va_list args;
|
||||
__builtin_sysv_va_start(args, format);
|
||||
const int result = LibcDetail::PrintWindows(format, args);
|
||||
__builtin_sysv_va_end(args);
|
||||
return result;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int APS5_VABI vsprintf_s_nid_postfix(char* buffer, size_t size, const char* format, VaList* args) {
|
||||
return std::vsnprintf(buffer, size, format, *reinterpret_cast<std::va_list*>(args));
|
||||
}
|
||||
|
||||
int APS5_VABI sprintf_s_nid_postfix(char* buffer, size_t size, const char* format, ...) {
|
||||
std::va_list args;
|
||||
va_start(args, format);
|
||||
const int result = std::vsnprintf(buffer, size, format, args);
|
||||
va_end(args);
|
||||
return result;
|
||||
}
|
||||
|
||||
int APS5_VABI snprintf_s_nid_postfix(char* buffer, size_t size, const char* format, ...) {
|
||||
std::va_list args;
|
||||
va_start(args, format);
|
||||
const int result = std::vsnprintf(buffer, size, format, args);
|
||||
va_end(args);
|
||||
return result;
|
||||
}
|
||||
|
||||
int APS5_VABI printf_s_nid_postfix(const char* format, ...) {
|
||||
std::va_list args;
|
||||
va_start(args, format);
|
||||
const int result = std::vprintf(format, args);
|
||||
va_end(args);
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int APS5_VABI puts_nid_postfix(const char* s) {
|
||||
return std::puts(s);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -143,6 +143,9 @@ int APS5_VABI tolower_nid_postfix(int c) { return ConvertCharacter(c, false); }
|
|||
std::uint64_t _ZNSt5ctypeIcE2idE_nid_postfix = 0;
|
||||
std::uint64_t _ZNSt5ctypeIwE2idE_nid_postfix = 0;
|
||||
std::uint64_t _ZNSt7collateIwE2idE_nid_postfix = 0;
|
||||
std::uint64_t _ZNSt7collateIcE2idE_nid_postfix = 0;
|
||||
std::uint64_t _ZNSt7codecvtIcc9_MbstatetE2idE_nid_postfix = 0;
|
||||
std::uintptr_t _ZTVSt7codecvtIcc9_MbstatetE_nid_postfix[16] {};
|
||||
std::uint64_t _ZNSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE2idE_nid_postfix = 0;
|
||||
std::uintptr_t _ZTVSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE_nid_postfix[12] {};
|
||||
|
||||
|
|
@ -185,6 +188,10 @@ void APS5_VABI _ZNSt7collateIwE7_GetcatEPPKNSt6locale5facetEPKS1__nid_postfix(Gu
|
|||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
|
||||
void APS5_VABI _ZNSt7collateIcE7_GetcatEPPKNSt6locale5facetEPKS1__nid_postfix(GuestLocale::Facet**, const GuestLocale::Implementation*) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
|
||||
void APS5_VABI _ZNSt8_LocinfoC1EPKc_nid_postfix(GuestLocale::LocinfoStorage* self, const char* localeName) {
|
||||
if (self == nullptr || localeName == nullptr || std::strcmp(localeName, "C") != 0) throw std::invalid_argument("_Locinfo: only the C locale is supported");
|
||||
new (self) GuestLocale::LocinfoStorage{};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
#include <iterator>
|
||||
#include <cstdlib>
|
||||
#include <stdexcept>
|
||||
#include <functional>
|
||||
|
|
@ -6,6 +8,9 @@
|
|||
#include <mutex>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <random>
|
||||
#include <string>
|
||||
#include <cinttypes>
|
||||
|
||||
#include "prx/libc/include/General.hpp"
|
||||
#include "prx/libc/include/specifics/gcc/AtomicOps.hpp"
|
||||
|
|
@ -15,6 +20,16 @@ namespace {
|
|||
|
||||
std::recursive_mutex g_sysLock;
|
||||
|
||||
struct ExitDestructor {
|
||||
void (*func)(void*);
|
||||
void* arg;
|
||||
void* dsoHandle;
|
||||
};
|
||||
|
||||
std::mutex g_exitMutex;
|
||||
std::vector<ExitDestructor> g_exitDestructors;
|
||||
bool g_exitRunnerRegistered = false;
|
||||
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
|
@ -24,21 +39,31 @@ FileStream _Stdout_nid_postfix{stdout};
|
|||
FileStream _Stdin_nid_postfix{stdin};
|
||||
|
||||
int APS5_VABI __cxa_atexit_nid_postfix(void (*func)(void*), void* arg, void* dsoHandle) {
|
||||
(void)dsoHandle;
|
||||
static std::vector<std::pair<void (*)(void*), void*>> destructors;
|
||||
static bool runnerRegistered = false;
|
||||
destructors.emplace_back(func, arg);
|
||||
if (!runnerRegistered) {
|
||||
runnerRegistered = true;
|
||||
std::atexit([] {
|
||||
for (auto it = destructors.rbegin(); it != destructors.rend(); ++it) {
|
||||
it->first(it->second);
|
||||
}
|
||||
});
|
||||
std::lock_guard lock(g_exitMutex);
|
||||
g_exitDestructors.push_back({func, arg, dsoHandle});
|
||||
if (!g_exitRunnerRegistered) {
|
||||
g_exitRunnerRegistered = true;
|
||||
std::atexit([] { CxaFinalize_nid_no_patch(nullptr); });
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CxaFinalize_nid_no_patch(void* dsoHandle) {
|
||||
for (;;) {
|
||||
ExitDestructor destructor{};
|
||||
{
|
||||
std::lock_guard lock(g_exitMutex);
|
||||
const auto found = std::find_if(g_exitDestructors.rbegin(), g_exitDestructors.rend(), [&](const ExitDestructor& entry) {
|
||||
return dsoHandle == nullptr || entry.dsoHandle == dsoHandle;
|
||||
});
|
||||
if (found == g_exitDestructors.rend()) return;
|
||||
destructor = *found;
|
||||
g_exitDestructors.erase(std::next(found).base());
|
||||
}
|
||||
destructor.func(destructor.arg);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int APS5_VABI _Atomic_fetch_add_4_nid_postfix(volatile unsigned int* target, unsigned int value, int memoryOrder) {
|
||||
(void)memoryOrder;
|
||||
return GccAtomicFetchAdd(target, value);
|
||||
|
|
@ -49,6 +74,50 @@ unsigned int APS5_VABI _Atomic_fetch_sub_4_nid_postfix(volatile unsigned int* ta
|
|||
return GccAtomicFetchSub(target, value);
|
||||
}
|
||||
|
||||
int APS5_VABI _Atomic_compare_exchange_weak_4_nid_postfix(volatile unsigned int* target, unsigned int* expected, unsigned int desired, int successOrder, int failureOrder) {
|
||||
(void)successOrder;
|
||||
(void)failureOrder;
|
||||
return GccAtomicCompareExchangeWeak(target, expected, desired) ? 1 : 0;
|
||||
}
|
||||
|
||||
unsigned int APS5_VABI _Atomic_load_4_nid_postfix(volatile unsigned int* target, int memoryOrder) {
|
||||
(void)memoryOrder;
|
||||
return GccAtomicLoad(target);
|
||||
}
|
||||
|
||||
std::uintmax_t APS5_VABI strtoumax_nid_postfix(const char* str, char** endptr, int base) {
|
||||
return std::strtoumax(str, endptr, base);
|
||||
}
|
||||
|
||||
unsigned int APS5_VABI _ZSt14_Random_devicev_nid_postfix() {
|
||||
static std::random_device device;
|
||||
static std::mutex mutex;
|
||||
std::lock_guard lock(mutex);
|
||||
return device();
|
||||
}
|
||||
|
||||
[[noreturn]] void APS5_VABI _ZSt14_Throw_C_errori_nid_postfix(int code) {
|
||||
throw std::runtime_error("_Throw_C_error: C11 thread error " + std::to_string(code));
|
||||
}
|
||||
|
||||
void APS5_VABI _Lockfilelock_nid_postfix(FileStream* stream) {
|
||||
if (stream == nullptr) throw std::invalid_argument("_Lockfilelock: null stream");
|
||||
#ifdef _WIN32
|
||||
_lock_file(GetNativeStream(stream));
|
||||
#else
|
||||
flockfile(GetNativeStream(stream));
|
||||
#endif
|
||||
}
|
||||
|
||||
void APS5_VABI _Unlockfilelock_nid_postfix(FileStream* stream) {
|
||||
if (stream == nullptr) throw std::invalid_argument("_Unlockfilelock: null stream");
|
||||
#ifdef _WIN32
|
||||
_unlock_file(GetNativeStream(stream));
|
||||
#else
|
||||
funlockfile(GetNativeStream(stream));
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned long APS5_VABI _Stoul_nid_postfix(const char* str, char** endptr, int base) {
|
||||
return std::strtoul(str, endptr, base);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "prx/libc/include/FileStream.hpp"
|
||||
#include "prx/libc/include/GuestHeap.hpp"
|
||||
#include "prx/libc/include/ApplicationHeap.hpp"
|
||||
#include "prx/libc/include/General.hpp"
|
||||
#include "SceTypes.hpp"
|
||||
|
||||
|
|
@ -19,6 +20,10 @@ using GuestNewHandler = void (APS5_VABI*)();
|
|||
|
||||
GuestNewHandler g_newHandler = nullptr;
|
||||
|
||||
void* Allocate(std::size_t size) {
|
||||
return ApplicationHeapAllocate_nid_no_patch(size == 0 ? 1 : size);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
|
@ -58,6 +63,44 @@ GuestNewHandler APS5_VABI _ZSt15set_new_handlerPFvvE_nid_postfix(GuestNewHandler
|
|||
return previous;
|
||||
}
|
||||
|
||||
GuestNewHandler APS5_VABI _ZSt15get_new_handlerv_nid_postfix() {
|
||||
return g_newHandler;
|
||||
}
|
||||
|
||||
unsigned char _ZSt7nothrow_nid_postfix = 0;
|
||||
|
||||
void* APS5_VABI _Znwm_nid_postfix(std::size_t size) {
|
||||
return Allocate(size);
|
||||
}
|
||||
|
||||
void* APS5_VABI _Znam_nid_postfix(std::size_t size) {
|
||||
return Allocate(size);
|
||||
}
|
||||
|
||||
void* APS5_VABI _ZnwmRKSt9nothrow_t_nid_postfix(std::size_t size, const void*) {
|
||||
return Allocate(size);
|
||||
}
|
||||
|
||||
void* APS5_VABI _ZnamRKSt9nothrow_t_nid_postfix(std::size_t size, const void*) {
|
||||
return Allocate(size);
|
||||
}
|
||||
|
||||
void APS5_VABI _ZdlPv_nid_postfix(void* pointer) {
|
||||
if (pointer != nullptr) ApplicationHeapFree_nid_no_patch(pointer);
|
||||
}
|
||||
|
||||
void APS5_VABI _ZdaPv_nid_postfix(void* pointer) {
|
||||
if (pointer != nullptr) ApplicationHeapFree_nid_no_patch(pointer);
|
||||
}
|
||||
|
||||
void APS5_VABI _ZdlPvm_nid_postfix(void* pointer, std::size_t) {
|
||||
if (pointer != nullptr) ApplicationHeapFree_nid_no_patch(pointer);
|
||||
}
|
||||
|
||||
void APS5_VABI _ZdaPvm_nid_postfix(void* pointer, std::size_t) {
|
||||
if (pointer != nullptr) ApplicationHeapFree_nid_no_patch(pointer);
|
||||
}
|
||||
|
||||
void APS5_VABI _ZdlPvSt11align_val_t_nid_postfix(void* pointer, std::size_t alignment) {
|
||||
(void)alignment;
|
||||
GuestHeap::GuestHeapFree_nid_postfix(pointer);
|
||||
|
|
|
|||
|
|
@ -188,6 +188,79 @@ int APS5_VABI strncpy_s_nid_postfix(char* dest, size_t destsz, const char* src,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI strcpy_s_nid_postfix(char* dest, size_t destsz, const char* src) {
|
||||
return strncpy_s_nid_postfix(dest, destsz, src, static_cast<size_t>(-1));
|
||||
}
|
||||
|
||||
int APS5_VABI strncat_s_nid_postfix(char* dest, size_t destsz, const char* src, size_t count) {
|
||||
constexpr int GuestEinval = 22;
|
||||
constexpr int GuestErange = 34;
|
||||
if (!dest || destsz == 0) return GuestEinval;
|
||||
size_t used = 0;
|
||||
while (used < destsz && dest[used] != '\0') ++used;
|
||||
if (used == destsz || !src) {
|
||||
dest[0] = '\0';
|
||||
return used == destsz ? GuestErange : GuestEinval;
|
||||
}
|
||||
size_t length = 0;
|
||||
while (length < count && src[length] != '\0') ++length;
|
||||
if (length >= destsz - used) {
|
||||
dest[0] = '\0';
|
||||
return GuestErange;
|
||||
}
|
||||
std::memcpy(dest + used, src, length);
|
||||
dest[used + length] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI strcat_s_nid_postfix(char* dest, size_t destsz, const char* src) {
|
||||
return strncat_s_nid_postfix(dest, destsz, src, static_cast<size_t>(-1));
|
||||
}
|
||||
|
||||
int APS5_VABI memcpy_s_nid_postfix(void* dest, size_t destsz, const void* src, size_t count) {
|
||||
constexpr int GuestEinval = 22;
|
||||
constexpr int GuestErange = 34;
|
||||
if (!dest) return GuestEinval;
|
||||
if (!src || count > destsz) {
|
||||
std::memset(dest, 0, destsz);
|
||||
return src ? GuestErange : GuestEinval;
|
||||
}
|
||||
std::memcpy(dest, src, count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI memmove_s_nid_postfix(void* dest, size_t destsz, const void* src, size_t count) {
|
||||
constexpr int GuestEinval = 22;
|
||||
constexpr int GuestErange = 34;
|
||||
if (!dest) return GuestEinval;
|
||||
if (!src || count > destsz) {
|
||||
std::memset(dest, 0, destsz);
|
||||
return src ? GuestErange : GuestEinval;
|
||||
}
|
||||
std::memmove(dest, src, count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI memset_s_nid_postfix(void* dest, size_t destsz, int value, size_t count) {
|
||||
constexpr int GuestEinval = 22;
|
||||
constexpr int GuestErange = 34;
|
||||
if (!dest) return GuestEinval;
|
||||
const auto length = count > destsz ? destsz : count;
|
||||
auto* bytes = static_cast<volatile unsigned char*>(dest);
|
||||
for (size_t index = 0; index < length; ++index) bytes[index] = static_cast<unsigned char>(value);
|
||||
return count > destsz ? GuestErange : 0;
|
||||
}
|
||||
|
||||
char* APS5_VABI strnstr_nid_postfix(const char* haystack, const char* needle, size_t length) {
|
||||
const size_t needleLength = std::strlen(needle);
|
||||
if (needleLength == 0) return const_cast<char*>(haystack);
|
||||
for (size_t index = 0; index < length && haystack[index] != '\0'; ++index) {
|
||||
if (needleLength > length - index) break;
|
||||
if (std::strncmp(haystack + index, needle, needleLength) == 0) return const_cast<char*>(haystack + index);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
unsigned long long APS5_VABI _Stoull_nid_postfix(const char* str, char** endptr, int base) {
|
||||
return std::strtoull(str, endptr, base);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -89,6 +89,10 @@ size_t APS5_VABI libc_strftime_nid_postfix(char* str, size_t count, const char*
|
|||
return std::strftime(str, count, format, timeptr);
|
||||
}
|
||||
|
||||
char* APS5_VABI asctime_nid_postfix(const std::tm* timeptr) {
|
||||
return std::asctime(timeptr);
|
||||
}
|
||||
|
||||
size_t APS5_VABI strftime_nid_postfix(char* str, size_t count, const char* format, const std::tm* timeptr) {
|
||||
return std::strftime(str, count, format, timeptr);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,13 @@
|
|||
#include <limits>
|
||||
#include <stdexcept>
|
||||
|
||||
extern "C" {
|
||||
void* APS5_VABI _Znwm_nid_postfix(std::size_t);
|
||||
void* APS5_VABI _ZnamRKSt9nothrow_t_nid_postfix(std::size_t, const void*);
|
||||
void APS5_VABI _ZdlPv_nid_postfix(void*);
|
||||
void APS5_VABI _ZdaPv_nid_postfix(void*);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
alignas(64) std::array<std::byte, 256> storage{};
|
||||
|
|
@ -117,7 +124,15 @@ int main(int argc, char**) {
|
|||
require(ApplicationHeapPosixAlign_nid_no_patch(&pointer, 64, 128) == 0 && pointer == storage.data() && lastAlignment == 64);
|
||||
reject([] { ApplicationHeapAlign_nid_no_patch(3, 64); });
|
||||
reject([] { ApplicationHeapCalloc_nid_no_patch(2, std::numeric_limits<std::size_t>::max()); });
|
||||
require(_Znwm_nid_postfix(0) == storage.data() && lastSize == 1);
|
||||
_ZdlPv_nid_postfix(storage.data());
|
||||
_ZdlPv_nid_postfix(nullptr);
|
||||
require(frees == 3);
|
||||
require(_ZnamRKSt9nothrow_t_nid_postfix(24, nullptr) == storage.data() && lastSize == 24);
|
||||
_ZdaPv_nid_postfix(storage.data());
|
||||
require(frees == 4);
|
||||
fail = true;
|
||||
reject([] { _Znwm_nid_postfix(8); });
|
||||
reject([] { ApplicationHeapAlign_nid_no_patch(4, 64); });
|
||||
reject([] { ApplicationHeapAllocate_nid_no_patch(64); });
|
||||
void* unchanged = storage.data();
|
||||
|
|
|
|||
|
|
@ -15,6 +15,14 @@ std::size_t APS5_VABI strlcat_nid_postfix(char*, const char*, std::size_t);
|
|||
char* APS5_VABI strtok_r_nid_postfix(char*, const char*, char**);
|
||||
char* APS5_VABI strtok_nid_postfix(char*, const char*);
|
||||
char* APS5_VABI strcasestr_nid_postfix(const char*, const char*);
|
||||
int APS5_VABI strcpy_s_nid_postfix(char*, std::size_t, const char*);
|
||||
int APS5_VABI strcat_s_nid_postfix(char*, std::size_t, const char*);
|
||||
int APS5_VABI strncat_s_nid_postfix(char*, std::size_t, const char*, std::size_t);
|
||||
int APS5_VABI memcpy_s_nid_postfix(void*, std::size_t, const void*, std::size_t);
|
||||
int APS5_VABI memmove_s_nid_postfix(void*, std::size_t, const void*, std::size_t);
|
||||
int APS5_VABI memset_s_nid_postfix(void*, std::size_t, int, std::size_t);
|
||||
char* APS5_VABI strnstr_nid_postfix(const char*, const char*, std::size_t);
|
||||
int APS5_VABI snprintf_s_nid_postfix(char*, std::size_t, const char*, ...);
|
||||
}
|
||||
|
||||
static void Require(bool condition) {
|
||||
|
|
@ -24,7 +32,31 @@ static void Require(bool condition) {
|
|||
}
|
||||
}
|
||||
|
||||
static void CheckBoundsCheckedFunctions() {
|
||||
char small[4] = "zz";
|
||||
Require(strcpy_s_nid_postfix(small, sizeof(small), "abc") == 0 && std::strcmp(small, "abc") == 0);
|
||||
Require(strcpy_s_nid_postfix(small, sizeof(small), "abcd") == 34 && small[0] == '\0');
|
||||
Require(strcpy_s_nid_postfix(nullptr, 4, "a") == 22);
|
||||
char joined[8] = "ab";
|
||||
Require(strcat_s_nid_postfix(joined, sizeof(joined), "cd") == 0 && std::strcmp(joined, "abcd") == 0);
|
||||
Require(strncat_s_nid_postfix(joined, sizeof(joined), "efgh", 2) == 0 && std::strcmp(joined, "abcdef") == 0);
|
||||
Require(strcat_s_nid_postfix(joined, sizeof(joined), "gh") == 34 && joined[0] == '\0');
|
||||
char bytes[4] = {1, 2, 3, 4};
|
||||
const char source[4] = {5, 6, 7, 8};
|
||||
Require(memcpy_s_nid_postfix(bytes, sizeof(bytes), source, 2) == 0 && bytes[0] == 5 && bytes[2] == 3);
|
||||
Require(memcpy_s_nid_postfix(bytes, 2, source, 4) == 34 && bytes[0] == 0 && bytes[1] == 0 && bytes[2] == 3);
|
||||
char overlap[6] = "abcde";
|
||||
Require(memmove_s_nid_postfix(overlap + 1, 5, overlap, 3) == 0 && std::strcmp(overlap, "aabce") == 0);
|
||||
Require(memset_s_nid_postfix(bytes, sizeof(bytes), 9, 8) == 34 && bytes[3] == 9);
|
||||
Require(strnstr_nid_postfix("haystack", "st", 4) == nullptr);
|
||||
const char haystack[] = "haystack";
|
||||
Require(strnstr_nid_postfix(haystack, "st", 6) == haystack + 3);
|
||||
char formatted[8];
|
||||
Require(snprintf_s_nid_postfix(formatted, sizeof(formatted), "%d-%s", 42, "x") == 4 && std::strcmp(formatted, "42-x") == 0);
|
||||
}
|
||||
|
||||
int main() {
|
||||
CheckBoundsCheckedFunctions();
|
||||
Require(std::strcmp(basename_nid_postfix(nullptr), ".") == 0);
|
||||
Require(std::strcmp(basename_nid_postfix(""), ".") == 0);
|
||||
Require(std::strcmp(basename_nid_postfix("////"), "/") == 0);
|
||||
|
|
|
|||
Loading…
Reference in New Issue