Skip to content
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

perlembed demos has SEGV risks, ithreads + setjmp + PERL_SET_CONTEXT are too dangerous to use #22901

Open
bulk88 opened this issue Jan 9, 2025 · 0 comments

Comments

@bulk88
Copy link
Contributor

bulk88 commented Jan 9, 2025

Description

I was looking ancient p5p code, and found PERL_FLEXIBLE_EXCEPTIONS it was removed long ago, but it used Win32 C++ exceptions or MS's C89 SEH exceptions. https://www.nntp.perl.org/group/perl.perl5.porters/2004/07/msg93069.html

Some IRC talk happened, and I've realized perlembed.pod has a large amount of unsafe demo code. Specifically calling into the perl XS API, without a root PP eval frame (jmpenv_t). A test showed that will be a "panic; top_env" not a SEGV as I originally thought. But still, "panic; top_env" doesn't separate P5P internals's emitting "panic; top_env" from bad root proc XS code emitting "panic; top_env".

Still worse, Perl_set_context()/PERL_SET_CONTEXT(), does nothing to disable, still active, jmpbuf_t'es collected from the PREVIOUS OS THREAD in the current my_perl/ithread. Perl_set_context()/PERL_SET_CONTEXT() does nothing to disable jmpbuf_t'es of the previous ithread if any. nGinx/CGI/GUI thread pool r real use cases for suspending/swapping OS threads between my_perls.

Very rare, but undiagnosable, what if a C++ exception erases the C stack frames of PP code (p5p C code), or XS modules (cpan' c code) unaware, are 5 layers deep in C stack frames and PP stack frames, in nested BEGIN {} blocks at use; time?

See IRC chatlog for details that MS's 1993-ucrtbase.dll setjmp() is too dangerous to use because of C++ and C89 SEH objects. And a peculiar MS choice, that C++/C89 SEH frames get "event objects" from 100%/ALL executions of longjmp(), but setjmp()/longjmp()/jmpbuf_t get 0 events going back. Win32 has the minimum-that-passed-CI, setjmp() impl, written for the "C abtract VM" and not a real win32 proc.

I dont see any way around this, except to sample the very proprietary "OS cur tid ", and keep it next to each jmpbuf_t struct, on every OS. perhaps even on no-threads perl, because no-threads perl can still be moved between OS threads (synchronously/safe and blocking-ish).

Perl's Configure needs logic to detect C stack grows up, down, or is a pure voodoo linked list malloc implementation. I can't think of any other way to detect "higher" former-C call stack frames that are now uninit memory Because someone threw a C++ exception but didnt kill the process yet.

In addition to the big 3 (Win/Lin/OSX) [# 2 android, # 3BSD], how do we support all the unix, esp commercial unixes, or dont? the posix world isn't entirely libpthreads.so or go home.

Callstacks with test # 1, the "sleeper" proc, RtlRaiseStatus() was passed error code 0xC0000028 STATUS_BAD_STACK, and generated a long crash callstack insite active running OS this # 2.

ntdll.dll!RtlRaiseStatus�()
ntdll.dll!string "Enabling heap debug options\n"�()
ntdll.dll!RtlUnwind�()
vcruntime140.dll!__longjmp_internal() Line 141
perl541.dll!Perl_die_unwind(interpreter * my_perl, sv * msv) Line 2108	C++
perl541.dll!Perl_croak_sv(interpreter * my_perl, sv * baseex) Line 1856	C++
perl541.dll!Perl_die_sv(interpreter * my_perl, sv * baseex) Line 1775	C++
perl541.dll!Perl_pp_die(interpreter * my_perl) Line 639	C++
perl541.dll!Perl_runops_standard(interpreter * my_perl) Line 41	C++
perl541.dll!Perl_call_sv(interpreter * my_perl, sv * sv, long arg_flags) Line 3236	C++
setcxt_pl_4840.dll!newRunner(void * p) Line 17	C++
kernel32.dll!BaseThreadInitThunk�()
ntdll.dll!RtlUserThreadStart�()

The infinity sleep root thread

ntdll.dll!NtDelayExecution�()
KernelBase.dll!SleepEx()
setcxt_pl_4840.dll!switch_osthd(unsigned __int64 test) Line 46	C++
setcxt_pl_4840.dll!XS_main_switch_osthd(interpreter * my_perl, cv * cv) Line 62	C++
[Inline Frame] perl541.dll!Perl_rpp_invoke_xs(interpreter *) Line 1177	C++
perl541.dll!Perl_pp_entersub(interpreter * my_perl) Line 6529	C++
perl541.dll!Perl_runops_standard(interpreter * my_perl) Line 41	C++
perl541.dll!S_run_body(interpreter * my_perl, long oldscope) Line 2885	C++
perl541.dll!perl_run(interpreter * my_perl) Line 2798	C++
perl541.dll!RunPerl(int argc, char * * argv, char * * env) Line 206	C++
[Inline Frame] perl.exe!invoke_main() Line 78	C++
perl.exe!__scrt_common_main_seh() Line 288	C++
kernel32.dll!BaseThreadInitThunk�()
ntdll.dll!RtlUserThreadStart�()

Test # 2 is less interesting, root thread is on purpose gone/dealloced already by the time of the crash.

Unhandled exception thrown: read access violation.
my_perl->Itop_env was 0x2AFD30.
If there is a handler for this exception, the program may be safely continued.

perl541.dll!Perl_call_sv(interpreter * my_perl, sv * sv, long arg_flags) Line 3170	C++
setcxt_pl_d3cd.dll!newRunner(void * p) Line 17	C++
kernel32.dll!BaseThreadInitThunk�()
ntdll.dll!RtlUserThreadStart�()

Steps to Reproduce

Change for your OS.

 use Inline  'noclean';

use Inline C => Config =>
  PRE_HEAD => '#define PERL_NO_GET_CONTEXT 1',
;
 use Inline C => Config => BUILD_NOISY => 1;
 use Inline C => <<'END_OF_C_CODE';
 
static DWORD WINAPI newRunner(LPVOID p) {
    void ** pa = (void **)p;
    dTHXa(pa[0]);
    PERL_SET_CONTEXT(aTHX);
    Sleep(500);
    {
        dSP;
        PUSHMARK(SP);
        PUTBACK;
        call_pv("do_die", G_DISCARD);
        croak(" unreachable !!!! ");
        ExitThread(1);
    }
    return 1;/*silence*/
}

void switch_osthd(UV test) {
    dTHX;
    void * parr[3]; // future, [1] maybe a mutex to sleep on, [2] IDK what
    HANDLE thd;
    parr[0] = (void *)aTHX;
    warn("entered xsub switch_osthd() with test type %" UVf "\n", test);
    thd = CreateThread(NULL,0,newRunner,(LPVOID)&parr,0,NULL);
    CloseHandle(thd); //or WFSO() on it??
    if(test == 1)
        Sleep(INFINITE);
    else if(test == 2)
        ExitThread(0);
    else if(test == 3)
        croak("good croak from XS switch_osthd()");
    else
        croak("XS switch_osthd(): arg 1 'UV test' test_type unknown");
}
 
END_OF_C_CODE

sub do_die {
    warn "entered sub do_die {} ";
    die "throwing the die";
}

{   my $died = eval { switch_osthd(2); };#test type, only values 1 or 2 or 3 allowed
    warn( (!defined($died) ? "did get (ok)" : "did not get (bad)")
          ." a die(), \$@=$@"
    );
}

Expected behavior

Throwing a PP perl exception after an ithread/my_perl was detached/attached to another OS thread, using perlembed.pod's public API, will print a "panic :" to console+exit process, not a SEGV popup that 90% of users can't diagnose. Separating P5P bugs from CPAN XS bugs is #2 priority. Example of an ancient P5P caused crash/panic, https://www.perlmonks.org/?node_id=331565 and also this #10441 for CPAN/community bugs google top_env perl.

PP->CPAN XS->C++ "bsearch"->CPAN XS->PP->CPAN XS->C++ std::SomeClass->C++ exception\|/
            /|\---------------------------------------------------------------------------------------------------

also needs to be detected/fatal console error/"silently" "fix it" and "continue execution" C-wise (PERL_FLEXIBLE_EXCEPTIONS), because that C problem was fixed and is now a high level $@ scalar / PP die() exception object.

Perl configuration

Summary of my perl5 (revision 5 version 41 subversion 7) configuration:
  Derived from: 73172a67eaae5671dffc06b427f005810d151472
  Platform:
    osname=MSWin32
    osvers=6.1.7601
    archname=MSWin32-x64-multi-thread
    uname=''
    config_args='undef'
    hint=recommended
    useposix=true
    d_sigaction=undef
    useithreads=define
    usemultiplicity=define
    use64bitint=define
    use64bitall=undef
    uselongdouble=undef
    usemymalloc=n
    default_inc_excludes_dot=define
  Compiler:
    cc='cl'
    ccflags ='-nologo -GF -W3 -MD -TP -EHsc -std:c++20 -DWIN32 -D_CONSOLE -DNO_S
TRICT -DWIN64 -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE -D_WINSOCK_
DEPRECATED_NO_WARNINGS -DPERL_TEXTMODE_SCRIPTS -DMULTIPLICITY -DPERL_IMPLICIT_SY
S -DWIN32_NO_REGISTRY -DUSE_PERLIO'
    optimize='-O1 -Zi -GL -fp:precise'
    cppflags='-DWIN32'
    ccversion='19.36.32535'
    gccversion=''
    gccosandvers=''
    intsize=4
    longsize=4
    ptrsize=8
    doublesize=8
    byteorder=12345678
    doublekind=3
    d_longlong=undef
    longlongsize=8
    d_longdbl=define
    longdblsize=8
    longdblkind=0
    ivtype='__int64'
    ivsize=8
    nvtype='double'
    nvsize=8
    Off_t='__int64'
    lseeksize=8
    alignbytes=8
    prototype=define
  Linker and Libraries:
    ld='link'
    ldflags ='-nologo -nodefaultlib -debug -opt:ref,icf -ltcg -libpath:"c:\pb64\
lib\CORE" -machine:AMD64 -subsystem:console,"5.02"'
    libpth="C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSV
C\14.36.32532\\lib\x64"
    libs=oldnames.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.li
b advapi32.lib shell32.lib ole32.lib oleaut32.lib netapi32.lib uuid.lib ws2_32.l
ib mpr.lib winmm.lib version.lib odbc32.lib odbccp32.lib comctl32.lib msvcrt.lib
 vcruntime.lib ucrt.lib
    perllibs=oldnames.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg3
2.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib netapi32.lib uuid.lib ws2_
32.lib mpr.lib winmm.lib version.lib odbc32.lib odbccp32.lib comctl32.lib msvcrt
.lib vcruntime.lib ucrt.lib
    libc=ucrt.lib
    so=dll
    useshrplib=true
    libperl=perl541.lib
    gnulibc_version=''
  Dynamic Linking:
    dlsrc=dl_win32.xs
    dlext=dll
    d_dlsymun=undef
    ccdlflags=' '
    cccdlflags=' '
    lddlflags='-dll -nologo -nodefaultlib -debug -opt:ref,icf -ltcg -libpath:"c:
\pb64\lib\CORE" -machine:AMD64 -subsystem:console,"5.02"'


Characteristics of this binary (from libperl):
  Compile-time options:
    HAS_LONG_DOUBLE
    HAS_TIMES
    HAVE_INTERP_INTERN
    MULTIPLICITY
    PERLIO_LAYERS
    PERL_COPY_ON_WRITE
    PERL_DONT_CREATE_GVSV
    PERL_HASH_FUNC_SIPHASH13
    PERL_HASH_USE_SBOX32
    PERL_IMPLICIT_SYS
    PERL_MALLOC_WRAP
    PERL_OP_PARENT
    PERL_PRESERVE_IVUV
    PERL_USE_SAFE_PUTENV
    USE_64_BIT_INT
    USE_ITHREADS
    USE_LARGE_FILES
    USE_LOCALE
    USE_LOCALE_COLLATE
    USE_LOCALE_CTYPE
    USE_LOCALE_NUMERIC
    USE_LOCALE_TIME
    USE_NO_REGISTRY
    USE_PERLIO
    USE_PERL_ATOF
    USE_THREAD_SAFE_LOCALE
  Locally applied patches:
    uncommitted-changes
  Built under MSWin32
  Compiled at Dec 20 2024 10:03:46
  @INC:
    C:/pb64/site/lib
    C:/pb64/lib

This IRC log was trimmed and paraphrased, except for my lines, but contains more of the details on setjmp/P_S_C(), and ways to fix.

<bulk88> hmm, was doing archaeology, PERL_FLEXIBLE_EXCEPTIONS (libc.setjmp() -> Linux GCC C++ try{}/catch{} [really ISO C++ spec's try{}/catch{}])
<bulk88> Looking at PERL_SET_CONTEXT()/Perl_set_context(), what invalidates all the longjmp_buf_t'es on the PP scope stack, if the perl proc, switches OS threads? An XS mod or embedder did it using public P5 API.
<> Yeah, try/catch sounds a little too tight for what we need to do
<bulk88> Im more thinking about MS's plain C SEH API, Win32/64 Perl is already compatible with it (no weird JIT), MS's setjmp()/longjmp() already unwind C++ frames and Dtor C++ objs if any in a Perl proc, and setjmp()/longjmp() are SEH internally anyway
<bulk88> I can't find the bug tickets/ML posts b/c google link rot, but I think  PERL_FLEXIBLE_EXCEPTIONS died, b/c core's Perl_set_context() forgot to wipe/invalidate flag, all the jumbuf_t'es
<bulk88> and the interp interestingly, refuses to EVER recording an integer called "tid" lol
<bulk88> a jmpbuf_t is uninit memory without recording the thread_id it was sampled with, if the app/proc/framework/code base permits creating OS threads
<> Probably because an interpreter can switch threads. Most famously it actually does during thread startup
<> S_ithread_create in threads.xs
<bulk88> right, so P_S_C() must push XSomething onto a stack, saying all jmpbuf_t'es before save_stack_ix_foo, are temp invalid (untrap print panic and exit proc), along with the new OS thread_id
<bulk88> perl core has no way of knowing if the old OS thread is suspended timeslots until X minutes/hours later, or old OS thread was freed, along with its C stack
<bulk88> webservers, thread pooling, a GUI/TUI IDE with 2 plugins in 1 OS proc, both plugins using libperl, and both plugins are unaware of each other
<bulk88> Coro/Lehman's frameworks too
<bulk88> my test case I randomly thought of, what stops the interp/core, when doing a eval{} die("");, from SEGVing, or what interp code, makes doing a cross OS thread, PP code " eval{}; die("");" actually safe?
<bulk88> https://perldoc.perl.org/perlembed#Performing-Perl-pattern-matches-and-substitutions-from-your-C-program
<bulk88> perlembed also cargo cult-ed a ticking timebomb, of running the interp instance, without a eval/die/setjmp frame of last resort
<bulk88> text = newSV(0);
<bulk88> sv_setpv(text, "When he is at a convenience store and the ");
<bulk88> perlembed's sample code, from C main(), called sv_setpv() and documented the entire public API, func wise, can execute without a PP eval frame of last resort
<bulk88> even if perl_parse()/perl_run() are good citizens, SvPV() and SvIV() don't set up PP eval frames
<bulk88> I've thought for years, PERL_SYS_INIT3 macro needs a secret setjmp() in it. Since a PERL_SYS_INIT/PERL_SYS_TERM pair, look perfect to slide in, secret MS C89 try{}/catch{} syntax if Perl's setjmp() exceptions are ever turned into formal MS-C89 SEH exceptions.
<bulk88> seems perl always guarded against an embedded without a PP eval frame, see https://github.com/Perl/perl5/blob/blead/cop.h#L61
<bulk88> but "panic: top_env" in STDERR, in the console, is a terrible diag message, and it doesn't instantly separate P5P bugs, vs end user's/cpan's problem bugs, since an embedder's C main() frame doesnt have a specific "its the embedder" indentity
<bulk88> also https://github.com/Perl/perl5/blob/blead/cop.h#L163 JMPENV_JUMP(arg1) doesn't have any protection against jumping into a future/deeper/now-invalid/former C stack frame, b/c unbalanced POP/PUSHes in CPAN XS or CORE
<bulk88> doing the highly illegal crime, of recording abs pointers of C stack args, saving those pointers into perl's jmpenv_t, along with current TID, should be done
<bulk88> note that comparing &c_stk_args, is a war crime in C abstract VM, since C doesn't define if the C stack grows upwards or downwards as an int, or the C stack is a linked list of malloc blocks, but maybe its time to break the law vs a SEGV
<bulk88> and C++ code can silently throw/jmp through P5P controlled, and 3rd party code
<> bulk88: how hard is it to make test cases that demonstrate this is really broken?
<bulk88> https://lists.mimedefang.org/pipermail/mimedefang_lists.mimedefang.org/2010-February/115850.html
<bulk88> https://github.com/perl/perl5/issues/8975
<bulk88> https://www.perlmonks.org/?node_id=368099
<bulk88> the community has triggered "panic: top_env" many times, P5P bugs, or their own XS bugs
<> bulk88: are those cases entered into core perl tests?
<shadowpaste> "bulk88" at pasted "Perl_set_context() OS Thd CHAOS example" (61 lines) at http://paste.scsys.co.uk/RMVED
<dipsy> [ magnet_web paste from "bulk88" at ... ] 
<bulk88> play around with the sample or port it to pthreads, only real gonna crash tests are UV 1 and UV 2
<> if these things can crash perl, can they be tested and, maybe, fixed?
<bulk88> test UV 1 models a "most innocent" "most accidental" bug, UV 2 is models a high throughput production "nginix" / "apache" threadpool bug
<bulk88> "crash perl, they should be captured in tests and, maybe, fixed?" IIRC its forbidden for P5P self make test, to "prove" the interp core dump/SIGBUS/SEGV as a test pass
<bulk88> supposedly some platforms/various community CI builders, hate that since it creates many 100MBs dump files in /home, that perl doesn't know about
<> my thinking was the SEGV would be prevented
<bulk88> fixing Perl_set_context(), I sorta can think of some improvements, I can definently make Perl_set_context() bulletproof on Win32, but theres alot of portability and new XS public/p5 private API design problems
<bulk88> a big one is, P5P perl currently has no idea what "int thread_id" is in a posix or any os portable way
<> do you have an idea?
<> how does cpython deal with this?
<bulk88> #include "pthreads.h" on "Unix" is as proprietary as #include "windows.h", since "int thread_id" is completely alien to POSIX and libc
<bulk88> https://pubs.opengroup.org/onlinepubs/7908799/xsh/pthread_self.html
<> ah, 'pthread_t' right?
<bulk88> pthread_t pthread_self(void)
<bulk88> is maximum "not a portable" spec as you can get, or just call it Linux proprietary
<> well, that's a POSIX doc & spec, not linux
<> does windows have an equivalent?
<bulk88> python has the GIL, its illegal to transfer control to libpython.so from 2 simul OS threads
<bulk88> IDK if cpython uses setjmp() or ever samples CPU registers as normal control flow (
<bulk88>  pthread_t pthread_self(void)) is GetCurrentThreadId() on Win32,
<> is there a way to define `PerlOSThreadId_t` for each of those?
<bulk88> GetCurrentThreadId() internally is exactly 3 x86 CPU ops, just 3x pointer derefs, stupid cheap, stupid fast, its the FS/GS registers, just like a sane pthreads lib on Linux
<> you're saying it's expensive on linux?
<bulk88> PerlOSThreadId_t? yes you can,  but each P5 platform, will need a volunteer to add the backend, and the boogie man is, what about ithreads-not-supported Unix'es? like if Configure reports OS threads not avail, but that weird commercial Unix, really does have OS threads
<bulk88> a no-threads-libperl, can still get moved between OS threads by someone's code
<> my thought for that type would just be to generalise between POSIX and Windows threads, no more. if the platform doesn't have one of those, nothing to be done, nothing lost
<bulk88> Win32/Linux/OSX are 98% of the world ATM, android is Linux and FreeBSD is OSX
<bulk88> its only VMS/AIX/solaris/hpux/etc that have problems
<bulk88> https://github.com/search?q=repo%3Alattera/glibc%20THREAD_SELF&type=code
<bulk88> pthread_self(() is asm code on all (almost?) all pthread  CPUs/Unixes
<> ok, i'm not seeing why that matters here?
<bulk88> so extreme fast and cheap, not a kernel call
<> i'm sure it does! just not comprehending
<bulk88> PerlOSTID_t for rare commercial Unixes is more of a wishlist/trollist/close the bug ticket thing than a push to blead blocker
<> what is the problem that means Perl can't stop some/all of these SEGVs?
<bulk88> exotic unix will keep SEGVing just like current situation, but 98% of users will get a panic message instead a segv
<bulk88> which is a huge improvement
<> sometimes one has to give up, but a good error message is worth a lot
<bulk88> also im not qualified to answer the security/exploit question of, are PIDs/TIDs randomized enough to be secure anti-repeat values, after the PID/TID is "freed" at kernel/backend/libc front end level?
<bulk88> if a PID/TID is like a unix FD, which struggles to get above int 10 or int 30, and instantly get reused, they aren't indentifiers of anything
<bulk88> if after a posix waitpid(), does the spec allow the XYZ Posix kernel to instantly reissue the PID value for the next process created on that box?
<> "POSIX prohibits the re-use of a process ID where a process group with that identifier still exists"
<bulk88> IDK enough internals of posix, my knowledge ends at, kernel metadata and the pid will stay around forever until some process executes C func waitpid()
<bulk88> http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/sys/kern/kern_fork.c.diff?r1=1.7&r2=1.8&f=h
<bulk88> prior to 1997 OpenBSD had "insecure PIDs"", insecure is self declared
<bulk88> these segvs are 99% caused by non p5p code, since threads.xs and psuedofork are tested to death/well maintained as is by p5p
<> of course, there's only so much one can do to stop people crashing their programs
<bulk88> IMHO, thread_id capture only covers 50% of segv risks, perl has to do C stack position capture also, so its impossible to jump into a ex-deeper-now_uninit memory C stack frame
<bulk88> perl 5 can't ask for C++ automatic dtor execution, when c++ autos go out of scope
<> is there anything it *could* do towards that?
<bulk88> thats the bullet proof way, to make sure a C89/99/c++ return can never leave a perl jmpenv_t snapshot half-alive
<> how would it do so?
<bulk88> I can think of ways, but the tomato throwing mob, will protest capturing and comparing positions on the C stack
<bulk88> and HPUX's C stack grows numerically upward like perl's @_ stack, while everything else grows numerically down
<bulk88> "grows numerically down" is so ISO C func arguments, and va_start() ... and friends, can blind cast between void ** type and a va_args_t  type
<bulk88> and my_call(5,4,3,2,1); stays as execution order in ISO C
<bulk88> va_start() va_end() va_copy() might be internally doing a malloc() and flipping around all the C stack args, without a C dev knowing
<bulk88> alien random pure C libs,  accepting user C callback fns, and the alien C lib itself doing setjmp()/longjmp(), zero integration with perl, its extremely scary to me
<bulk88> same for C++ try catch frames, perl is unaware of C++ and C++ is unaware of setjmp(), and spec authors decided, "user error, get the malware [from cpan or apt-get] out of your process"
<bulk88> https://linux.die.net/man/3/dlopen is not part of ISO C or C++, RFC ticket rejected
<> there's probably a few who'd agree C++ is malware
<bulk88> there is a large opinion in GNU/BSD core C lib projects, that the user compiled his own executable process, and has 100% full control over all  code except for glibc.so in his virtual memory space
<bulk88> plugin architectures like perl 5, and .so files are too unprofessional to entertain supporting
<bulk88> "if you can't debug C code, or step debug a linux kernel driver, you should hire a professional to operator your new PDP-11"
<bulk88> if a certain family member was at home, I wouldve put a photo right now of a pdp-11 assembly book and the camel book, the DAT tapes are somewhere also with the source code
<bulk88> MS CRT's setjmp() internally captures 11 vanilla general purpose CPU regs, &(jmp_buf* Buf), &(((void**)(Buf))[-1]), SSE MCREG (master control reg 64b), x87 legacy MCREG 64b, 10 128bit SSE regs, return; /* 's */
<bulk88> 00xF0 or 0xFF bytes of CPU registers on AMD64
<bulk88>  public API MS CRT's longjmp, internaly sanity checks that, previously captured  ptr "&(jmp_buf* Buf)", is between the current OS thread's C stack's 4096-byte-units start address, and dynamically stretched/grown current 4096-byte-unit end address
<bulk88> "end address" will ALWAYS BE UNINIT memory, end address is the last/highest currently alloced 4KB page in the current Win32 OS thread's C stack pre-reserved range, so bounds checking anything against that 4096-aligned address, isn't that safe, because 0-4096 bytes worth of FUTURE C stack frames, are always garbage bytes.
<bulk88> If the user passed jmpbuf_t *, fails the security bounds test, IE Perl 5 and Perl_set_context() drama
<bulk88> MS Libc basically will do a SEGV, and pop up the  Windows GUI segv box, nobody will learn the real error code unless they attach a C debugger and learn its "SIG __fastfail(0xd) " not a SEGV/BUS/ILL
<bulk88> if jmpbuf_t * passes sanitizing checks, longjmp() fires STATUS_LONGJMP 0x80000026 exception objects at all SEH frame objects, until those SEH objects are freed
<bulk88> IDK how  C89 exception object 0x80000026 shows up in ISO C++
<bulk88> after all C++/SEH frames are nuked, 10+2+11 CPU regs are restored, and JMP op back to Perl/XS
<bulk88> MS's/Win32's setjmp()/longjmp() is too dangerous in anything production/realistic, b/c longjmp() sends "events" to all C++ objects, but C++ and MS C89/99/23 SEH don't send "events" to setjmp()
<bulk88> MS's/Win32's setjmp()/longjmp() was written to pass the CI test suite, for "C99/C23 abstract virtual machine" and nothing else
<bulk88> switch (PerlProc_setjmp(cur_env.je_buf, SCOPE_SAVES_SIGNAL_MASK)) {
<bulk88> case 0: cur_env.je_ret = 0; break;
<bulk88> default: Perl_croak(aTHX_ "panic: unexpected setjmp() result\n");
<bulk88> }
<bulk88> very little to change in generic P5 core, to replace setjmp with SEH frames, if P5 ever gets any kind of exception object, in ()'es of catch(){} the message is already sitting there
<bulk88> I dont think its sane to continue the process, or repair the "process state" if private/CPAN XS called into a C++ lib that threw a C++ object, game over, you lost.
<bulk88> if that XS mod, was buggy/too beta-ish, to remember to capture C++ exceptions, when that XS mod fully knows its calling "::" C++ functions, there isn't anyway for the perl proc to continue
<> bulk88: makes sense, thank you
<> it's a pity perl can't engage in that C++ bit though
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant