Skip to content

mg.c: Perl_magic_get() dont call libc's getter func _errno() over and over #23370

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: blead
Choose a base branch
from

Conversation

bulk88
Copy link
Contributor

@bulk88 bulk88 commented Jun 13, 2025

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.


///////////     BEFORE
#endif  /* End of platforms with special handling for $^E; others just fall
           through to $! */
        }
    /* FALLTHROUGH */
    case '!':
        {
            dSAVE_ERRNO;
000007FE93BE5B6F FF 15 1B 5B 04 00    call        qword ptr [__imp__errno (07FE93C2B690h)]  
000007FE93BE5B75 8B 30                mov         esi,dword ptr [rax]  
000007FE93BE5B77 FF 15 B3 57 04 00    call        qword ptr [__imp_GetLastError (07FE93C2B330h)]  
000007FE93BE5B7D 8B E8                mov         ebp,eax  
#ifdef VMS
            sv_setnv(sv, (NV)((errno == EVMSERR) ? vaxc$errno : errno));
#else
            sv_setnv(sv, (NV)errno);
000007FE93BE5B7F FF 15 0B 5B 04 00    call        qword ptr [__imp__errno (07FE93C2B690h)]  
000007FE93BE5B85 48 8B D7             mov         rdx,rdi  
000007FE93BE5B88 48 8B CB             mov         rcx,rbx  
000007FE93BE5B8B 66 0F 6E 10          movd        xmm2,dword ptr [rax]  
000007FE93BE5B8F F3 0F E6 D2          cvtdq2pd    xmm2,xmm2  
000007FE93BE5B93 E8 34 84 F6 FF       call        Perl_sv_setnv (07FE93B4DFCCh)  
#endif
#ifdef OS2
            if (errno == errno_isOS2 || errno == errno_isOS2_set)
                sv_setpv(sv, os2error(Perl_rc));
            else
#endif
            if (! errno) {
000007FE93BE5B98 FF 15 F2 5A 04 00    call        qword ptr [__imp__errno (07FE93C2B690h)]  
000007FE93BE5B9E 44 39 38             cmp         dword ptr [rax],r15d  
000007FE93BE5BA1 75 13                jne         $add_groups+536h (07FE93BE5BB6h)  
                SvPVCLEAR(sv);
000007FE93BE5BA3 45 33 C9             xor         r9d,r9d  
000007FE93BE5BA6 45 33 C0             xor         r8d,r8d  
000007FE93BE5BA9 48 8B D7             mov         rdx,rdi  
000007FE93BE5BAC 48 8B CB             mov         rcx,rbx  
000007FE93BE5BAF E8 D8 CE F6 FF       call        Perl_sv_setpv_bufsize (07FE93B52A8Ch)  
            }
000007FE93BE5BB4 EB 23                jmp         $add_groups+559h (07FE93BE5BD9h)  
            else {
                sv_string_from_errnum(errno, sv);
000007FE93BE5BB6 FF 15 D4 5A 04 00    call        qword ptr [__imp__errno (07FE93C2B690h)]  
000007FE93BE5BBC 4C 8B C7             mov         r8,rdi  
000007FE93BE5BBF 48 8B CB             mov         rcx,rbx  
000007FE93BE5BC2 8B 10                mov         edx,dword ptr [rax]  
000007FE93BE5BC4 E8 17 F6 FF FF       call        Perl_sv_string_from_errnum (07FE93BE51E0h)  
                /* 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 */
                if (!SvCUR(sv))
000007FE93BE5BC9 48 8B 07             mov         rax,qword ptr [rdi]  
000007FE93BE5BCC 4C 39 78 10          cmp         qword ptr [rax+10h],r15  
000007FE93BE5BD0 75 07                jne         $add_groups+559h (07FE93BE5BD9h)  
                    SvPOK_off(sv);
000007FE93BE5BD2 81 67 0C FF BB FF FF and         dword ptr [rdi+0Ch],0FFFFBBFFh  
            }
            RESTORE_ERRNO;
000007FE93BE5BD9 FF 15 B1 5A 04 00    call        qword ptr [__imp__errno (07FE93C2B690h)]  
000007FE93BE5BDF 8B CD                mov         ecx,ebp  
000007FE93BE5BE1 89 30                mov         dword ptr [rax],esi  
000007FE93BE5BE3 FF 15 57 57 04 00    call        qword ptr [__imp_SetLastError (07FE93C2B340h)]  
        }
        SvRTRIM(sv);
000007FE93BE5BE9 BD 00 04 00 00       mov         ebp,400h  
000007FE93BE5BEE 85 6F 0C             test        dword ptr [rdi+0Ch],ebp  
000007FE93BE5BF1 0F 84 40 FA FF FF    je          Perl_magic_get+30Bh (07FE93BE5637h)  
000007FE93BE5BF7 4C 8B 17             mov         r10,qword ptr [rdi]  
000007FE93BE5BFA 4C 8B 4F 10          mov         r9,qword ptr [rdi+10h]  
000007FE93BE5BFE 49 8B 4A 10          mov         rcx,qword ptr [r10+10h]  
000007FE93BE5C02 48 85 C9             test        rcx,rcx  
000007FE93BE5C05 0F 84 24 FA FF FF    je          Perl_magic_get+303h (07FE93BE562Fh)  
000007FE93BE5C0B 49 8D 51 FF          lea         rdx,[r9-1]  
000007FE93BE5C0F BE 01 00 00 00       mov         esi,1  
000007FE93BE5C14 48 03 D1             add         rdx,rcx  
000007FE93BE5C17 4C 8D 35 E2 A3 EE FF lea         r14,[`gai_strerrorW'::`2'::buff (07FE93AD0000h)]  
000007FE93BE5C1E 41 B8 00 44 00 00    mov         r8d,4400h  
000007FE93BE5C24 0F B6 02             movzx       eax,byte ptr [rdx]  
000007FE93BE5C27 41 8B 84 86 B0 E3 2D 00 mov         eax,dword ptr [r14+rax*4+2DE3B0h]  
000007FE93BE5C2F 41 23 C0             and         eax,r8d  
000007FE93BE5C32 41 3B C0             cmp         eax,r8d  
000007FE93BE5C35 0F 85 F4 F9 FF FF    jne         Perl_magic_get+303h (07FE93BE562Fh)  
000007FE93BE5C3B 48 2B D6             sub         rdx,rsi  
000007FE93BE5C3E 48 2B CE             sub         rcx,rsi  
000007FE93BE5C41 75 E1                jne         $add_groups+5A4h (07FE93BE5C24h)  
        SvNOK_on(sv);	/* what a wonderful hack! */
        break;
000007FE93BE5C43 E9 E7 F9 FF FF       jmp         Perl_magic_get+303h (07FE93BE562Fh)  
    case '\027':		/* ^W  & $^WARNING_BITS */
        if (nextchar == '\0')
000007FE93BE5C48 84 D2                test        dl,dl  
000007FE93BE5C4A 75 11                jne         $add_groups+5DDh (07FE93BE5C5Dh)  
            sv_setiv(sv, (IV)cBOOL(PL_dowarn & G_WARN_ON));
000007FE93BE5C4C 44 0F B6 83 B4 00 00 00 movzx       r8d,byte ptr [rbx+0B4h]  
000007FE93BE5C54 49 83 E0 01          and         r8,1  
000007FE93BE5C58 E9 23 FA FF FF       jmp         $add_groups (07FE93BE5680h)  
        else if (strEQ(remaining, "ARNING_BITS")) {
000007FE93BE5C5D 48 8D 15 9C 2E 1F 00 lea         rdx,[string "ARNING_BITS" (07FE93DD8B00h)]  
000007FE93BE5C64 48 8B CE             mov         rcx,rsi  
000007FE93BE5C67 FF 15 4B 5C 04 00    call        qword ptr [__imp_strcmp (07FE93C2B8B8h)]  
////////// AFTER
#endif  /* End of platforms with special handling for $^E; others just fall
           through to $! */
        }
    /* FALLTHROUGH */
    case '!':
        {
            dSAVE_ERRNO;
000007FE93F65B6F FF 15 1B 5B 04 00    call        qword ptr [__imp__errno (07FE93FAB690h)]  
000007FE93F65B75 8B 30                mov         esi,dword ptr [rax]  
000007FE93F65B77 FF 15 B3 57 04 00    call        qword ptr [__imp_GetLastError (07FE93FAB330h)]  
000007FE93F65B7D 66 0F 6E D6          movd        xmm2,esi  
#ifdef VMS
            sv_setnv(sv, (NV)((saved_errno == EVMSERR) ? vaxc$errno : saved_errno));
#else
            sv_setnv(sv, (NV)saved_errno);
000007FE93F65B81 48 8B D7             mov         rdx,rdi  
000007FE93F65B84 F3 0F E6 D2          cvtdq2pd    xmm2,xmm2  
000007FE93F65B88 48 8B CB             mov         rcx,rbx  
000007FE93F65B8B 8B E8                mov         ebp,eax  
000007FE93F65B8D E8 3A 84 F6 FF       call        Perl_sv_setnv (07FE93ECDFCCh)  
#endif
#ifdef OS2
            if (saved_errno == errno_isOS2 || saved_errno == errno_isOS2_set)
                sv_setpv(sv, os2error(Perl_rc));
            else
#endif
            if (! saved_errno) {
000007FE93F65B92 48 8B CB             mov         rcx,rbx  
000007FE93F65B95 85 F6                test        esi,esi  
000007FE93F65B97 75 10                jne         $add_groups+529h (07FE93F65BA9h)  
                SvPVCLEAR(sv);
000007FE93F65B99 45 33 C9             xor         r9d,r9d  
000007FE93F65B9C 45 33 C0             xor         r8d,r8d  
000007FE93F65B9F 48 8B D7             mov         rdx,rdi  
000007FE93F65BA2 E8 E5 CE F6 FF       call        Perl_sv_setpv_bufsize (07FE93ED2A8Ch)  
            }
000007FE93F65BA7 EB 1A                jmp         $add_groups+543h (07FE93F65BC3h)  
            else {
                sv_string_from_errnum(saved_errno, sv);
000007FE93F65BA9 4C 8B C7             mov         r8,rdi  
000007FE93F65BAC 8B D6                mov         edx,esi  
000007FE93F65BAE E8 2D F6 FF FF       call        Perl_sv_string_from_errnum (07FE93F651E0h)  
                /* 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 */
                if (!SvCUR(sv))
000007FE93F65BB3 48 8B 07             mov         rax,qword ptr [rdi]  
000007FE93F65BB6 4C 39 78 10          cmp         qword ptr [rax+10h],r15  
000007FE93F65BBA 75 07                jne         $add_groups+543h (07FE93F65BC3h)  
                    SvPOK_off(sv);
000007FE93F65BBC 81 67 0C FF BB FF FF and         dword ptr [rdi+0Ch],0FFFFBBFFh  
            }
            RESTORE_ERRNO;
000007FE93F65BC3 FF 15 C7 5A 04 00    call        qword ptr [__imp__errno (07FE93FAB690h)]  
000007FE93F65BC9 8B CD                mov         ecx,ebp  
000007FE93F65BCB 89 30                mov         dword ptr [rax],esi  
000007FE93F65BCD FF 15 6D 57 04 00    call        qword ptr [__imp_SetLastError (07FE93FAB340h)]  
        }
        SvRTRIM(sv);
000007FE93F65BD3 BD 00 04 00 00       mov         ebp,400h  
000007FE93F65BD8 85 6F 0C             test        dword ptr [rdi+0Ch],ebp  
000007FE93F65BDB 0F 84 56 FA FF FF    je          Perl_magic_get+30Bh (07FE93F65637h)  
000007FE93F65BE1 4C 8B 17             mov         r10,qword ptr [rdi]  
000007FE93F65BE4 4C 8B 4F 10          mov         r9,qword ptr [rdi+10h]  
000007FE93F65BE8 49 8B 4A 10          mov         rcx,qword ptr [r10+10h]  
000007FE93F65BEC 48 85 C9             test        rcx,rcx  
000007FE93F65BEF 0F 84 3A FA FF FF    je          Perl_magic_get+303h (07FE93F6562Fh)  
000007FE93F65BF5 49 8D 51 FF          lea         rdx,[r9-1]  
000007FE93F65BF9 BE 01 00 00 00       mov         esi,1  
000007FE93F65BFE 48 03 D1             add         rdx,rcx  
000007FE93F65C01 4C 8D 35 F8 A3 EE FF lea         r14,[`gai_strerrorW'::`2'::buff (07FE93E50000h)]  
000007FE93F65C08 41 B8 00 44 00 00    mov         r8d,4400h  
000007FE93F65C0E 0F B6 02             movzx       eax,byte ptr [rdx]  
000007FE93F65C11 41 8B 84 86 B0 E3 2D 00 mov         eax,dword ptr [r14+rax*4+2DE3B0h]  
000007FE93F65C19 41 23 C0             and         eax,r8d  
000007FE93F65C1C 41 3B C0             cmp         eax,r8d  
000007FE93F65C1F 0F 85 0A FA FF FF    jne         Perl_magic_get+303h (07FE93F6562Fh)  
000007FE93F65C25 48 2B D6             sub         rdx,rsi  
000007FE93F65C28 48 2B CE             sub         rcx,rsi  
000007FE93F65C2B 75 E1                jne         $add_groups+58Eh (07FE93F65C0Eh)  
        SvNOK_on(sv);	/* what a wonderful hack! */
        break;
000007FE93F65C2D E9 FD F9 FF FF       jmp         Perl_magic_get+303h (07FE93F6562Fh)  
    case '\027':		/* ^W  & $^WARNING_BITS */
        if (nextchar == '\0')
000007FE93F65C32 84 D2                test        dl,dl  
000007FE93F65C34 75 11                jne         $add_groups+5C7h (07FE93F65C47h) 

  • This set of changes does not require a perldelta entry.

… 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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant