From 51a2783016ce5f48ce245db98a68d386f074d4bc Mon Sep 17 00:00:00 2001 From: bulk88 Date: Thu, 12 Jun 2025 17:56:51 -0400 Subject: [PATCH] mg.c: Perl_magic_get() dont call libc's getter func _errno() over and over Ever since threads and SMP motherboards were invented, C's grammer token errno has been a function call returning an int * and not a extern "C" global data variable. Whether C grammer token is an inline asm intrinsic macro, or a traditional linker symbol in the C lang's symbol table, doesn't matter. On Windows errno is a macro to int * _errno(void) from ucrtbase.dll The UCRT dll from its day 1 upto atleast the UCRT dllfrom Win 10 ~2019, has a severe multi-eval bug in its C++/CPP getter method for its core TLS fetcher function. The multi-eval problem involves GetProcAddress(), and dynamic dispatching between TlsGetValue() and FlsGetValue(), and the rule that non-inlined function calls may never be de-duped for any reason. C++ operator overloading and CPP #define will never turn 10 method calls in a .i file or C++ template, into 1 method call and 1 POD size_t/void * variable. VC6, all msvcrt.dlls thru VC 2013, correctly only execute TlsGetValue() once and cache the result. UCRT does not. A pathologic reading of the POSIX spec, guarentees sv_setnv() UBed the value inside errno, through some ISO C lexer token inside the sv.i file made from sv.c that defines the body of sv_setnv(). If libc.so is chmod to --x by root user, how can a user prove the machine code inside libc's memcpy() does not call libc's sqrt() function? All behavior is unspecified and valid until it is defined. A realistic, not pedantic, location where errno was UBed could be these 2 lines: SV_CHECK_THINKFIRST_COW_DROP(sv); sv_upgrade(sv, SVt_PVNV); This patch was written for Win32 perf reasons, and not POSIX/C compliance. The later are an afterthought. To fix all of the above, cache the retval of errno. The ticket for this patch has a before/after. --- mg.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mg.c b/mg.c index 98da1f15910c..7d8a5b6fa5c2 100644 --- a/mg.c +++ b/mg.c @@ -1009,20 +1009,20 @@ Perl_magic_get(pTHX_ SV *sv, MAGIC *mg) { dSAVE_ERRNO; #ifdef VMS - sv_setnv(sv, (NV)((errno == EVMSERR) ? vaxc$errno : errno)); + sv_setnv(sv, (NV)((saved_errno == EVMSERR) ? vaxc$errno : saved_errno)); #else - sv_setnv(sv, (NV)errno); + sv_setnv(sv, (NV)saved_errno); #endif #ifdef OS2 - if (errno == errno_isOS2 || errno == errno_isOS2_set) + if (saved_errno == errno_isOS2 || saved_errno == errno_isOS2_set) sv_setpv(sv, os2error(Perl_rc)); else #endif - if (! errno) { + if (! saved_errno) { SvPVCLEAR(sv); } else { - sv_string_from_errnum(errno, sv); + sv_string_from_errnum(saved_errno, sv); /* If no useful string is available, don't * claim to have a string part. The SvNOK_on() * below will cause just the number part to be valid */