Skip Menu |
Report information
Id: 118127
Status: open
Priority: 0/
Queue: perl5

Owner: Nobody
Requestors: kartlee05 <karthik.rajagopalan [at] schrodinger.com>
Cc: bulk88 <bulk88 [at] hotmail.com>
AdminCc:

Operating System: mswin32
PatchStatus: (no value)
Severity: low
Type: unknown
Perl Version: (no value)
Fixed In: (no value)

Attachments
0001-WIP-118127-don-t-closesocket-on-non-socket-handles-o.patch
0001-WIP-don-t-closesocket-on-non-socket-handles.patch



CC: Herc Silverstein <herc.silverstein [...] schrodinger.com>, Volker Eyrich <volker.eyrich [...] schrodinger.com>
Subject: Perl crash when run under AppVerifier
Date: Wed, 22 May 2013 16:56:58 -0400
To: perlbug [...] perl.org
From: Karthik Rajagopalan <karthik.rajagopalan [...] schrodinger.com>
Download (untitled) / with headers
text/plain 9.1k
Download (untitled) / with headers
text/html 11.5k
Hi Folks,

We use perl widely for one of our job monitoring application. And recently we received reports from customer that the application crash after few hours with 'invalid handle' exception in ntdll.dll.
So we planned to run our application in Application Verifier of Windows to trace handles and having a hard time to run perl under it. Currently the following piece of code extracted in the form of a sample script crash under AppVerifier -

use IO::Socket::INET;
use IPC::Open2;
my $log = "txt";
open OUT, -f $log ? ">> $log" : ">$log";
  
# Pass an open handle of tempfile to child process.
open FILE, ">temp";
binmode FILE;
print FILE "abc";
close FILE;
open IN, "temp";

print "here\n";
my $child_pid = open2(">&OUT","<&IN","(notepad.exe)2>&1");
print "here1\n";
close IN;
close OUT;

Exactly after notepad.exe process is spawned we see the crash with following stack trace. We see a similar trace at customer site when a handle is being closed through closesocket(..) call which is not really a socket handle. The stack trace given below is from perl-5.10.1. We also see a similar stack trace with 5.14.2. So I am sure this is a problem even in current running version of perl. Can you please take a look and respond back?

-Karthik



0:000> !analyze  -v
*******************************************************************************
*                                                                             *
*                        Exception Analysis                                   *
*                                                                             *
*******************************************************************************

*** WARNING: Unable to verify checksum for c:\Schrodinger2012_x64\latest\mmshare-v2.1\bin\Windows-x64\perl510.dll
*** WARNING: Unable to verify checksum for c:\Schrodinger2012_x64\latest\mmshare-v2.1\bin\Windows-x64\perl.exe
APPLICATION_VERIFIER_HANDLES_INVALID_HANDLE (300)
Invalid handle exception for current stack trace.
This stop is generated if the function on the top of the stack passed an
invalid handle to system routines. Usually a simple kb command will reveal
what is the value of the handle passed (must be one of the parameters -
usually the first one). If the value is null then this is clearly wrong.
If the value looks ok you need to use !htrace debugger extension to get a
history of operations pertaining to this handle value. In most cases it
must be that the handle value is used after being closed. 
Arguments:
Arg1: 00000000c0000008, Exception code. 
Arg2: 000000000108eaa0, Exception record. Use .exr to display it. 
Arg3: 000000000108e470, Context record. Use .cxr to display it. 
Arg4: 0000000000000000, Not used. 

FAULTING_IP: 
vrfcore!VerifierStopMessageEx+779
000007fe`f76637ed cc              int     3

EXCEPTION_RECORD:  000000000108eaa0 -- (.exr 0x108eaa0)
ExceptionAddress: 0000000077c5fec7 (ntdll!KiRaiseUserExceptionDispatcher+0x000000000000003a)
   ExceptionCode: c0000008 (Invalid handle)
  ExceptionFlags: 00000000
NumberParameters: 0
Thread tried to close a handle that was invalid or illegal to close

FAULTING_THREAD:  0000000000000ae8

DEFAULT_BUCKET_ID:  STATUS_BREAKPOINT

PROCESS_NAME:  perl.exe

CONTEXT:  000000000108e470 -- (.cxr 0x108e470)
rax=0000000031c7226f rbx=0000000000000000 rcx=000000000108e470
rdx=000007fef5663da5 rsi=0000000000000000 rdi=0000000000000003
rip=0000000077c5fec7 rsp=000000000108ea80 rbp=000000000108ebd0
 r8=000000000108eb48  r9=000000000108ebd0 r10=0000000000000000
r11=0000000000000202 r12=0000000000000000 r13=0000000000000000
r14=0000000000000000 r15=0000000000012043
iopl=0         nv up ei pl nz na po nc
cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
ntdll!KiRaiseUserExceptionDispatcher+0x3a:
00000000`77c5fec7 8b8424c0000000  mov     eax,dword ptr [rsp+0C0h] ss:00000000`0108eb40=c0000008
Resetting default scope

BAD_HANDLE: 0000000000000003 (!htrace 0000000000000003)

ERROR_CODE: (NTSTATUS) 0x80000003 - {EXCEPTION}  Breakpoint  A breakpoint has been reached.

EXCEPTION_CODE: (HRESULT) 0x80000003 (2147483651) - One or more arguments are invalid

EXCEPTION_PARAMETER1:  0000000000000000

MOD_LIST: <ANALYSIS/>

NTGLOBALFLAG:  100

APPLICATION_VERIFIER_FLAGS:  80000004

PRIMARY_PROBLEM_CLASS:  STATUS_BREAKPOINT

BUGCHECK_STR:  APPLICATION_FAULT_STATUS_BREAKPOINT

LAST_CONTROL_TRANSFER:  from 000007fef56578dd to 000007fef76637ed

STACK_TEXT:  
00000000`0108d970 000007fe`f56578dd : 00000000`0108dd10 00000000`77d48350 00000030`00000004 00000001`002b0000 : vrfcore!VerifierStopMessageEx+0x779
00000000`0108dca0 00000000`77c28a8f : 00000000`028f0dc0 00000000`eceeae86 00000000`77d48350 00000000`0618ccf9 : vfbasics!AVrfpVectoredExceptionHandler+0x85
00000000`0108dcf0 00000000`77c259b2 : 00000000`0000000e 00000000`00000000 00000000`00000080 00000000`028f0db0 : ntdll!RtlpCallVectoredHandlers+0xa8
00000000`0108dd60 00000000`77c262ee : 00000000`00000000 00000000`00000000 00000000`00000001 000007fe`00000015 : ntdll!RtlDispatchException+0x22
00000000`0108e440 00000000`77c5fec7 : 00000000`00000000 00000000`00000000 00000000`00000003 00000000`00033283 : ntdll!RtlRaiseException+0x221
00000000`0108ea80 000007fe`f5663da5 : 00000000`00000003 00000000`0108ec18 00000000`0108ec20 00000000`0108ec28 : ntdll!KiRaiseUserExceptionDispatcher+0x3a
00000000`0108eb50 000007fe`fd3c80d8 : 00000000`00000000 00000000`00000370 00000000`00000000 00000000`00000000 : vfbasics!AVrfpNtDeviceIoControlFile+0x171
00000000`0108ec10 000007fe`fd3abfe0 : 00000000`00000003 00000000`05941380 00000000`00000003 00000000`00000001 : mswsock!SockImportHandle+0x108
00000000`0108ee00 000007fe`fd3cbd19 : 00000000`00000003 00000000`05941380 00000000`00000006 00000000`02b57bf8 : mswsock!_GSHandlerCheck_SEH+0x408a
00000000`0108ee30 000007fe`fe797b7e : 00000000`00000003 000007fe`0000ffff 00000000`00000003 00000000`05941380 : mswsock!WSPGetSockOpt+0x99
00000000`0108ef10 000007fe`fe7ad71a : 00000000`05945590 00000000`00000000 00000000`05941380 00000000`02b50000 : WS2_32!DPROVIDER::WSPGetSockOpt+0x3e
00000000`0108ef50 000007fe`fe7ad7f0 : 00000000`00000208 00000000`00003c30 00000000`00000000 000007fe`fe781ac0 : WS2_32!DCATALOG::FindIFSProviderForSocket+0xca
00000000`0108f260 000007fe`fe7903fd : 00000000`00000001 00000000`00000000 00000000`00000000 000007fe`f565a64d : WS2_32!DSOCKET::FindIFSSocket+0x40
00000000`0108f290 00000000`6b8e4756 : 00000000`00000000 00000000`00000000 00000000`02b57bf8 00000000`00000001 : WS2_32!_chkstk+0x3ecb
00000000`0108f2e0 00000000`6b8f70da : 00000000`00000000 00000000`06107358 00000000`02b57bf8 00000000`040015b0 : perl510!my_close+0x36 [c:\perl\perl_with_fix-5.10.1\win32\win32sck.c @ 470]
00000000`0108f310 00000000`6b8f2a51 : 00000000`06107358 00000000`02b57bf8 00000000`040015b0 00000000`00000001 : perl510!PerlIOUnix_close+0x5a [c:\perl\perl_with_fix-5.10.1\perlio.c @ 2751]
00000000`0108f340 00000000`6b8f3257 : 00000000`040015b0 00000000`00000008 00000000`0108f4e0 00000000`6bdd8bc0 : perl510!PerlIOBase_close+0x91 [c:\perl\perl_with_fix-5.10.1\perlio.c @ 2181]
00000000`0108f370 00000000`6b8f37c7 : 00000000`00000008 00000000`040015b0 00000000`00000000 00000000`00000000 : perl510!PerlIOBuf_close+0x17 [c:\perl\perl_with_fix-5.10.1\perlio.c @ 4088]
00000000`0108f3a0 00000000`6b9e4256 : 00000000`00000008 00000000`00000002 00000000`0108f4e0 00000000`00000008 : perl510!Perl_PerlIO_close+0x37 [c:\perl\perl_with_fix-5.10.1\perlio.c @ 1432]
00000000`0108f3e0 00000000`6b96e84e : 00000000`04066440 00000000`6b980b3c 00000000`0615ec01 00000000`02b57bf8 : perl510!Perl_do_openn+0x1286 [c:\perl\perl_with_fix-5.10.1\doio.c @ 660]
00000000`0108f610 00000000`6b9e7f9c : 00000000`00000013 00000000`00000000 00000000`00000000 00000000`02b57bf8 : perl510!Perl_pp_open+0x27e [c:\perl\perl_with_fix-5.10.1\pp_sys.c @ 561]
00000000`0108f690 00000000`6b9a8c06 : 00000000`02b57bf8 00000000`03fb9ee0 00000000`00000001 00000000`03ec6660 : perl510!Perl_runops_standard+0x16c [c:\perl\perl_with_fix-5.10.1\run.c @ 40]
00000000`0108f700 00000000`6b9a8e94 : 00000000`02b57bf8 00000000`00000000 00000000`0108f6e0 00000000`03fb9ee0 : perl510!S_run_body+0x116 [c:\perl\perl_with_fix-5.10.1\perl.c @ 2433]
00000000`0108f730 00000000`6b8fd324 : 00000000`03fb39a0 00000000`03fba5a0 00000000`03fb9ee0 00000000`00000000 : perl510!perl_run+0x264 [c:\perl\perl_with_fix-5.10.1\perl.c @ 2352]
00000000`0108f8a0 00000001`3f0411b2 : 00000000`00000001 00000000`00000000 00000000`00000000 00000000`00000000 : perl510!RunPerl+0x124 [c:\perl\perl_with_fix-5.10.1\win32\perllib.c @ 270]
00000000`0108fcf0 00000000`77b0f56d : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : perl!__tmainCRTStartup+0x11a [f:\dd\vctools\crt_bld\self_64_amd64\crt\src\crtexe.c @ 555]
00000000`0108fd20 00000000`77c43281 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : kernel32!BaseThreadInitThunk+0xd
00000000`0108fd50 00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlUserThreadStart+0x1d


FOLLOWUP_IP: 
mswsock!SockImportHandle+108
000007fe`fd3c80d8 448bf8          mov     r15d,eax

SYMBOL_STACK_INDEX:  7

SYMBOL_NAME:  mswsock!SockImportHandle+108

FOLLOWUP_NAME:  MachineOwner

MODULE_NAME: mswsock

IMAGE_NAME:  mswsock.dll

DEBUG_FLR_IMAGE_TIMESTAMP:  4a5bdfc4

STACK_COMMAND:  ~0s ; kb

FAILURE_BUCKET_ID:  STATUS_BREAKPOINT_80000003_mswsock.dll!SockImportHandle

BUCKET_ID:  X64_APPLICATION_FAULT_STATUS_BREAKPOINT_mswsock!SockImportHandle+108

Followup: MachineOwner



RT-Send-CC: perl5-porters [...] perl.org
Download (untitled) / with headers
text/plain 2.9k
On Wed May 22 13:57:37 2013, kartlee05 wrote: Show quoted text
> Hi Folks, > > We use perl widely for one of our job monitoring application. And > recently > we received reports from customer that the application crash after few > hours with 'invalid handle' exception in ntdll.dll. > So we planned to run our application in Application Verifier of > Windows to > trace handles and having a hard time to run perl under it. Currently > the > following piece of code extracted in the form of a sample script crash > under AppVerifier -
.................................................... Show quoted text
> Exactly after notepad.exe process is spawned we see the crash with > following stack trace. We see a similar trace at customer site when a > handle is being closed through closesocket(..) call which is not > really a > socket handle. The stack trace given below is from perl-5.10.1. We > also see > a similar stack trace with 5.14.2. So I am sure this is a problem even > in > current running version of perl. Can you please take a look and > respond > back?
NT Kernel does not throw exceptions AKA crashes AKA SEH for STATUS_INVALID_HANDLE unless you turn on exotic debugging (GlobalFlag key in registry for that image path) for the process, see http://msdn.microsoft.com/en-us/library/windows/hardware/ff542881%28v=vs.85%29.aspx . That is what VS Debugger's invalid handle exceptions are. They are made only for debugging purposes and dont happen at normal runtime. STATUS_INVALID_HANDLE will be the returned error number for Native API call in kernel32. Your customer would never have a crash with STATUS_INVALID_HANDLE unless GlobalFlag is set in the registry by accident, or some non-MS and non-Perl code did a RaiseException. What my first guess is that this is a double free-ing of a socket handle. My second guess says this is by design, because in http://perl5.git.perl.org/perl.git/blob/HEAD:/win32/win32sck.c#l418 all unix FDs get closed as a winsock handle, then if winsock doesn't recognize it, then close it as a clib FD. The design I think is an artifact that under Dos Windows (especially 95, late in 98 SE and ME, winsock handles became kernel pipes I think), winsock handles were not kernel handles (WSAGetLastError vs GetLastError, on NT WSA version forwards to kernel32). On NT, all winsock handles are kernel pipe handles belonging to the AFD driver. Note, Win32's/Perl's pipes are implemented by a different driver called NPFS. So that is why this hack is used to separate sockets from pipes, http://jakash3.wordpress.com/2012/12/19/getting-file-descriptor-type-in-windows/ . Calling the generic CloseHandle on a socket is forbidden by MS's docs, so that is probably out of the question. I think the current code is fine. Someone can argue speed of finding out the handle type and closing it once vs blindly closing it with different libraries. 5.14 I think is now out of support since 5.18 was released a few days ago. I didn't run any code to write this post. -- bulk88 ~ bulk88 at hotmail.com
Subject: Re: [perl #118127] Perl crash when run under AppVerifier
Date: Wed, 5 Jun 2013 07:46:53 -0400
To: perlbug-followup [...] perl.org
From: Karthik Rajagopalan <karthik.rajagopalan [...] schrodinger.com>
Download (untitled) / with headers
text/plain 10.5k
Download (untitled) / with headers
text/html 13.4k
Hi,

Thanks for your reply. I don't think debugging flag is turned on at customer site. Otherwise you will see this when analyzing the dump ( NTGLOBALFLAG:  0
APPLICATION_VERIFIER_FLAGS:  0 ). BTW, the job monitor code we use is purely perl, so there is no confusion that non-perl code is causing the crash here or throwing exception. Please find below the new crash report we received. This seem to be coming win32's alarm implementation. Any thoughts about this crash?

-Karthik

0:000> !analyze -v
*******************************************************************************
*                                                                             *
*                        Exception Analysis                                   *
*                                                                             *
*******************************************************************************

*** ERROR: Symbol file could not be found.  Defaulted to export symbols for threads.dll - 
GetPageUrlData failed, server returned HTTP status 404

FAULTING_IP: 
ntdll!RtlRaiseStatus+18
00000000`76e0d7d8 488b8424b8010000 mov     rax,qword ptr [rsp+1B8h]

EXCEPTION_RECORD:  ffffffffffffffff -- (.exr 0xffffffffffffffff)
ExceptionAddress: 0000000076e0d7d8 (ntdll!RtlRaiseStatus+0x0000000000000018)
   ExceptionCode: c0000008 (Invalid handle)
  ExceptionFlags: 00000001
NumberParameters: 0
Thread tried to close a handle that was invalid or illegal to close

DEFAULT_BUCKET_ID:  INVALID_POINTER_READ

PROCESS_NAME:  perl.exe

ERROR_CODE: (NTSTATUS) 0xc0000008 - An invalid HANDLE was specified.

EXCEPTION_CODE: (NTSTATUS) 0xc0000008 - An invalid HANDLE was specified.

MOD_LIST: <ANALYSIS/>

NTGLOBALFLAG:  0

APPLICATION_VERIFIER_FLAGS:  0

FAULTING_THREAD:  0000000000001554

PRIMARY_PROBLEM_CLASS:  INVALID_POINTER_READ

BUGCHECK_STR:  APPLICATION_FAULT_INVALID_POINTER_READ

LAST_CONTROL_TRANSFER:  from 0000000076da8e59 to 0000000076e0d7d8

STACK_TEXT:  
00000000`0031de20 00000000`76da8e59 : 00000000`00000100 00000000`0031e670 00000000`00000000 00000000`0031e640 : ntdll!RtlRaiseStatus+0x18
00000000`0031e3c0 00000000`76d67e74 : 00000000`0031e600 00000000`00000000 00000000`c0150008 00000000`0031e600 : ntdll! ?? ::FNODOBFM::`string'+0x969e
00000000`0031e3f0 00000000`76d67b2e : 00000000`00000000 000007fe`fb9cbaf0 00000000`0031e690 000007fe`fd37d90d : ntdll!LdrpLoadDll+0x897
00000000`0031e600 000007fe`fd379aa9 : 00000000`00000000 00000000`00000000 000007fe`fb9cbaf0 00000000`00000062 : ntdll!LdrLoadDll+0x9a
00000000`0031e670 000007fe`fd37bc01 : 00000000`00000000 000007fe`fb9cbaf0 000007fe`fb9c5a10 00000000`00000000 : KERNELBASE!LoadLibraryExW+0x22e
00000000`0031e6e0 000007fe`fb98dffa : 00000000`00000000 00000065`00670061 00000000`00000000 00000000`00000000 : KERNELBASE!LoadLibraryExA+0x51
00000000`0031e730 000007fe`fb98dfb3 : 00000000`00000000 00000000`00000083 00000000`0049052a 00000000`00000001 : uxtheme!_delayLoadHelper2+0x96
00000000`0031e7c0 000007fe`fb98b192 : 00000000`0049052a 00000000`00010001 00000000`0031e860 00000000`00000004 : uxtheme!_tailMerge_dwmapi_dll+0x3f
00000000`0031e830 000007fe`fb9885a0 : 00000000`00000001 00000000`00000000 00000000`0049052a 00000000`00000083 : uxtheme!CThemeWnd::Reject+0x58
00000000`0031e860 000007fe`fb981607 : 00000000`00000000 00000000`00000083 00000000`00000000 00000000`0049052a : uxtheme!CThemeWnd::Attach+0x1cd
00000000`0031e8d0 000007fe`fb98b1c6 : 00000000`0031ec40 00000000`0049052a 00000000`00000000 00000000`0031ec40 : uxtheme!_ThemeDefWindowProc+0x133
00000000`0031e980 00000000`76c4aafc : 00000000`00000000 00000000`00000104 00000000`0031e9e8 00000000`0031e9f8 : uxtheme!ThemeDefWindowProcA+0xe
00000000`0031e9c0 00000000`6473b226 : 00000000`00000083 00000000`00000000 00000000`00000000 ffffffff`ffffffff : user32!DefWindowProcA+0xe6
00000000`0031ea10 00000000`76c59bd1 : 00000000`00000000 00000000`00000000 00000000`00000001 00000000`00000000 : perl514!win32_message_window_proc+0x46 [c:\perl\x64\perl-5.14.2\win32\win32.c @ 4450]
00000000`0031ea40 00000000`76c572cb : 00000000`00000000 00000000`6473b1e0 00000000`00000000 00000000`00000000 : user32!UserCallWinProcCheckWow+0x1ad
00000000`0031eb00 00000000`76c506e8 : 00000000`76c5041a ffffffff`ffff0000 00000000`6473b1e0 00000000`0031ec58 : user32!DispatchClientMessage+0xc3
00000000`0031eb60 00000000`76d91225 : 00000000`00000000 fffff880`08baf790 00000000`00000000 00000000`00000000 : user32!_fnINOUTNCCALCSIZE+0x3c
00000000`0031ebc0 00000000`76c5041a : 00000000`76c50397 00000000`0031f088 00000000`00000000 00000000`0031f088 : ntdll!KiUserCallbackDispatcherContinue
00000000`0031ec58 00000000`76c50397 : 00000000`0031f088 00000000`00000000 00000000`0031f088 00000000`0031f088 : user32!ZwUserCreateWindowEx+0xa
00000000`0031ec60 00000000`76c505d8 : 00000000`0000002e 00000000`80000000 00000000`00000000 00000000`00000000 : user32!VerNtUserCreateWindowEx+0x27c
00000000`0031efd0 00000000`76c4a350 : 00000000`00000000 00000000`64870558 00000000`003da340 00000000`0000003c : user32!CreateWindowEx+0x404
00000000`0031f120 00000000`6473b657 : 00000000`0000000e 00000000`00683368 00000000`0000000e 00000000`6482bfbe : user32!CreateWindowExA+0x70
00000000`0031f1a0 00000000`6473b6af : 00000000`00000000 00000000`02a0b1d0 00000000`005955a8 00000000`647dd9d9 : perl514!win32_create_message_window+0xa7 [c:\perl\x64\perl-5.14.2\win32\win32.c @ 4548]
00000000`0031f260 00000000`647bfd35 : 00000000`02a0b1d0 00000000`0363f910 00000000`003d33c8 00000000`00000001 : perl514!win32_alarm+0x3f [c:\perl\x64\perl-5.14.2\win32\win32.c @ 2342]
00000000`0031f290 00000000`647942a6 : 00000000`005955a8 00000000`00000000 00000000`00000002 00000000`005955a8 : perl514!Perl_pp_alarm+0x55 [c:\perl\x64\perl-5.14.2\pp_sys.c @ 4565]
00000000`0031f2c0 00000000`64807991 : 00000000`00000001 00000000`6474cef0 00000000`003dc140 00000000`005955a8 : perl514!Perl_runops_standard+0x16 [c:\perl\x64\perl-5.14.2\run.c @ 41]
00000000`0031f2f0 00000000`64807c24 : 00000000`005955a8 00000000`00000000 00000000`0031f2d0 00000000`003da340 : perl514!S_run_body+0x131 [c:\perl\x64\perl-5.14.2\win32\perl.c @ 2352]
00000000`0031f320 00000000`6474d291 : 00000000`003d4620 00000000`003dc140 00000000`003da340 00000000`00000000 : perl514!perl_run+0x264 [c:\perl\x64\perl-5.14.2\win32\perl.c @ 2271]
00000000`0031f490 00000001`3f5811b2 : 00000000`00000001 00000000`00000000 00000000`00000000 00000000`00000000 : perl514!RunPerl+0x151 [c:\perl\x64\perl-5.14.2\win32\perllib.c @ 270]
00000000`0031f8d0 00000000`7667652d : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : perl!__tmainCRTStartup+0x11a [f:\dd\vctools\crt_bld\self_64_amd64\crt\src\crtexe.c @ 555]
00000000`0031f900 00000000`76d6c521 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : kernel32!BaseThreadInitThunk+0xd
00000000`0031f930 00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlUserThreadStart+0x1d


STACK_COMMAND:  ~0s; .ecxr ; kb

FOLLOWUP_IP: 
uxtheme!_delayLoadHelper2+96
000007fe`fb98dffa 488bd8          mov     rbx,rax

SYMBOL_STACK_INDEX:  6

SYMBOL_NAME:  uxtheme!_delayLoadHelper2+96

FOLLOWUP_NAME:  MachineOwner

MODULE_NAME: uxtheme

IMAGE_NAME:  uxtheme.dll

DEBUG_FLR_IMAGE_TIMESTAMP:  4a5be093

FAILURE_BUCKET_ID:  INVALID_POINTER_READ_c0000008_uxtheme.dll!_delayLoadHelper2

BUCKET_ID:  X64_APPLICATION_FAULT_INVALID_POINTER_READ_uxtheme!_delayLoadHelper2+96


Followup: MachineOwner
---------










On Wed, May 22, 2013 at 11:04 PM, bulk88 via RT <perlbug-followup@perl.org> wrote:
Show quoted text
On Wed May 22 13:57:37 2013, kartlee05 wrote:
> Hi Folks,
>
> We use perl widely for one of our job monitoring application. And
> recently
> we received reports from customer that the application crash after few
> hours with 'invalid handle' exception in ntdll.dll.
> So we planned to run our application in Application Verifier of
> Windows to
> trace handles and having a hard time to run perl under it. Currently
> the
> following piece of code extracted in the form of a sample script crash
> under AppVerifier -
....................................................
> Exactly after notepad.exe process is spawned we see the crash with
> following stack trace. We see a similar trace at customer site when a
> handle is being closed through closesocket(..) call which is not
> really a
> socket handle. The stack trace given below is from perl-5.10.1. We
> also see
> a similar stack trace with 5.14.2. So I am sure this is a problem even
> in
> current running version of perl. Can you please take a look and
> respond
> back?

NT Kernel does not throw exceptions AKA crashes AKA SEH for
STATUS_INVALID_HANDLE unless you turn on exotic debugging (GlobalFlag
key in registry for that image path) for the process, see
http://msdn.microsoft.com/en-us/library/windows/hardware/ff542881%28v=vs.85%29.aspx
. That is what VS Debugger's invalid handle exceptions are. They are
made only for debugging purposes and dont happen at normal runtime.
STATUS_INVALID_HANDLE will be the returned error number for Native API
call in kernel32. Your customer would never have a crash with
STATUS_INVALID_HANDLE unless GlobalFlag is set in the registry by
accident, or some non-MS and non-Perl code did a RaiseException.

What my first guess is that this is a double free-ing of a socket
handle. My second guess says this is by design, because in
http://perl5.git.perl.org/perl.git/blob/HEAD:/win32/win32sck.c#l418 all
unix FDs get closed as a winsock handle, then if winsock doesn't
recognize it, then close it as a clib FD. The design I think is an
artifact that under Dos Windows (especially 95, late in 98 SE and ME,
winsock handles became kernel pipes I think), winsock handles were not
kernel handles (WSAGetLastError vs GetLastError, on NT WSA version
forwards to kernel32). On NT, all winsock handles are kernel pipe
handles belonging to the AFD driver. Note, Win32's/Perl's pipes are
implemented by a different driver called NPFS. So that is why this hack
is used to separate sockets from pipes,
http://jakash3.wordpress.com/2012/12/19/getting-file-descriptor-type-in-windows/
. Calling the generic CloseHandle on a socket is forbidden by MS's docs,
so that is probably out of the question. I think the current code is
fine. Someone can argue speed of finding out the handle type and closing
it once vs blindly closing it with different libraries.


5.14 I think is now out of support since 5.18 was released a few days
ago. I didn't run any code to write this post.

--
bulk88 ~ bulk88 at hotmail.com

RT-Send-CC: perl5-porters [...] perl.org
Download (untitled) / with headers
text/plain 6.5k
On Thu Jun 06 11:27:32 2013, kartlee05 wrote: Show quoted text
> Please find below the new crash > report we > received. This seem to be coming win32's alarm implementation. Any > thoughts > about this crash? > > -Karthik > > > STACK_TEXT: > 00000000`0031de20 00000000`76da8e59 : 00000000`00000100 > 00000000`0031e670 > 00000000`00000000 00000000`0031e640 : ntdll!RtlRaiseStatus+0x18 > 00000000`0031e3c0 00000000`76d67e74 : 00000000`0031e600 > 00000000`00000000 > 00000000`c0150008 00000000`0031e600 : ntdll! ?? > ::FNODOBFM::`string'+0x969e > 00000000`0031e3f0 00000000`76d67b2e : 00000000`00000000 > 000007fe`fb9cbaf0 > 00000000`0031e690 000007fe`fd37d90d : ntdll!LdrpLoadDll+0x897 > 00000000`0031e600 000007fe`fd379aa9 : 00000000`00000000 > 00000000`00000000 > 000007fe`fb9cbaf0 00000000`00000062 : ntdll!LdrLoadDll+0x9a > 00000000`0031e670 000007fe`fd37bc01 : 00000000`00000000 > 000007fe`fb9cbaf0 > 000007fe`fb9c5a10 00000000`00000000 : KERNELBASE!LoadLibraryExW+0x22e > 00000000`0031e6e0 000007fe`fb98dffa : 00000000`00000000 > 00000065`00670061 > 00000000`00000000 00000000`00000000 : KERNELBASE!LoadLibraryExA+0x51 > 00000000`0031e730 000007fe`fb98dfb3 : 00000000`00000000 > 00000000`00000083 > 00000000`0049052a 00000000`00000001 : uxtheme!_delayLoadHelper2+0x96 > 00000000`0031e7c0 000007fe`fb98b192 : 00000000`0049052a > 00000000`00010001 > 00000000`0031e860 00000000`00000004 : > uxtheme!_tailMerge_dwmapi_dll+0x3f > 00000000`0031e830 000007fe`fb9885a0 : 00000000`00000001 > 00000000`00000000 > 00000000`0049052a 00000000`00000083 : uxtheme!CThemeWnd::Reject+0x58 > 00000000`0031e860 000007fe`fb981607 : 00000000`00000000 > 00000000`00000083 > 00000000`00000000 00000000`0049052a : uxtheme!CThemeWnd::Attach+0x1cd > 00000000`0031e8d0 000007fe`fb98b1c6 : 00000000`0031ec40 > 00000000`0049052a > 00000000`00000000 00000000`0031ec40 : > uxtheme!_ThemeDefWindowProc+0x133 > 00000000`0031e980 00000000`76c4aafc : 00000000`00000000 > 00000000`00000104 > 00000000`0031e9e8 00000000`0031e9f8 : uxtheme!ThemeDefWindowProcA+0xe > 00000000`0031e9c0 00000000`6473b226 : 00000000`00000083 > 00000000`00000000 > 00000000`00000000 ffffffff`ffffffff : user32!DefWindowProcA+0xe6 > 00000000`0031ea10 00000000`76c59bd1 : 00000000`00000000 > 00000000`00000000 > 00000000`00000001 00000000`00000000 : > perl514!win32_message_window_proc+0x46 > [c:\perl\x64\perl-5.14.2\win32\win32.c @ 4450] > 00000000`0031ea40 00000000`76c572cb : 00000000`00000000 > 00000000`6473b1e0 > 00000000`00000000 00000000`00000000 : > user32!UserCallWinProcCheckWow+0x1ad > 00000000`0031eb00 00000000`76c506e8 : 00000000`76c5041a > ffffffff`ffff0000 > 00000000`6473b1e0 00000000`0031ec58 : > user32!DispatchClientMessage+0xc3 > 00000000`0031eb60 00000000`76d91225 : 00000000`00000000 > fffff880`08baf790 > 00000000`00000000 00000000`00000000 : user32!_fnINOUTNCCALCSIZE+0x3c > 00000000`0031ebc0 00000000`76c5041a : 00000000`76c50397 > 00000000`0031f088 > 00000000`00000000 00000000`0031f088 : > ntdll!KiUserCallbackDispatcherContinue > 00000000`0031ec58 00000000`76c50397 : 00000000`0031f088 > 00000000`00000000 > 00000000`0031f088 00000000`0031f088 : user32!ZwUserCreateWindowEx+0xa > 00000000`0031ec60 00000000`76c505d8 : 00000000`0000002e > 00000000`80000000 > 00000000`00000000 00000000`00000000 : > user32!VerNtUserCreateWindowEx+0x27c > 00000000`0031efd0 00000000`76c4a350 : 00000000`00000000 > 00000000`64870558 > 00000000`003da340 00000000`0000003c : user32!CreateWindowEx+0x404 > 00000000`0031f120 00000000`6473b657 : 00000000`0000000e > 00000000`00683368 > 00000000`0000000e 00000000`6482bfbe : user32!CreateWindowExA+0x70 > 00000000`0031f1a0 00000000`6473b6af : 00000000`00000000 > 00000000`02a0b1d0 > 00000000`005955a8 00000000`647dd9d9 : > perl514!win32_create_message_window+0xa7 > [c:\perl\x64\perl-5.14.2\win32\win32.c @ 4548] > 00000000`0031f260 00000000`647bfd35 : 00000000`02a0b1d0 > 00000000`0363f910 > 00000000`003d33c8 00000000`00000001 : perl514!win32_alarm+0x3f > [c:\perl\x64\perl-5.14.2\win32\win32.c @ 2342] > 00000000`0031f290 00000000`647942a6 : 00000000`005955a8 > 00000000`00000000 > 00000000`00000002 00000000`005955a8 : perl514!Perl_pp_alarm+0x55 > [c:\perl\x64\perl-5.14.2\pp_sys.c @ 4565] > 00000000`0031f2c0 00000000`64807991 : 00000000`00000001 > 00000000`6474cef0 > 00000000`003dc140 00000000`005955a8 : > perl514!Perl_runops_standard+0x16 > [c:\perl\x64\perl-5.14.2\run.c @ 41] > 00000000`0031f2f0 00000000`64807c24 : 00000000`005955a8 > 00000000`00000000 > 00000000`0031f2d0 00000000`003da340 : perl514!S_run_body+0x131 > [c:\perl\x64\perl-5.14.2\win32\perl.c @ 2352] > 00000000`0031f320 00000000`6474d291 : 00000000`003d4620 > 00000000`003dc140 > 00000000`003da340 00000000`00000000 : perl514!perl_run+0x264 > [c:\perl\x64\perl-5.14.2\win32\perl.c @ 2271] > 00000000`0031f490 00000001`3f5811b2 : 00000000`00000001 > 00000000`00000000 > 00000000`00000000 00000000`00000000 : perl514!RunPerl+0x151 > [c:\perl\x64\perl-5.14.2\win32\perllib.c @ 270] > 00000000`0031f8d0 00000000`7667652d : 00000000`00000000 > 00000000`00000000 > 00000000`00000000 00000000`00000000 : perl!__tmainCRTStartup+0x11a > [f:\dd\vctools\crt_bld\self_64_amd64\crt\src\crtexe.c @ 555] > 00000000`0031f900 00000000`76d6c521 : 00000000`00000000 > 00000000`00000000 > 00000000`00000000 00000000`00000000 : kernel32!BaseThreadInitThunk+0xd > 00000000`0031f930 00000000`00000000 : 00000000`00000000 > 00000000`00000000 > 00000000`00000000 00000000`00000000 : ntdll!RtlUserThreadStart+0x1d > >
Use Dependency Walker since something went wrong with loading a DLL. I'm not familiar with NT 6 DLL loader, I know more about the NT 5 DLL loader. I dont fully trust that call stack because of "::FNODOBFM::`string'" which seems to be garbage according to google. Also normally the callstacks have parameters (but they are garbage on x64 because of calling convention), but here all I see is offsets from functions. IIRC offsets from functions means the debugger is guessing the function call names by at the export table and calculating an offset from the closest exported function. Sometimes this is correct, sometimes its very wrong. _delayLoadHelper2 means a delay loaded dll, in this case dwmapi.dll. So, we are looking for why loading a DLL caused STATUS_INVALID_HANDLE, as an exception, instead of it winding up. Appverifier, a C debugger attached to the process, or a checked build are what I would try to rule out. The links below describe security software meddling with DLL loading. Googling STATUS_INVALID_HANDLE and loadlibraryex gave me http://forums.asp.net/t/1704958.aspx/7/10?Re+SEHException+thrown+when+I+run+the+application http://social.msdn.microsoft.com/Forums/en-US/vsdebug/thread/06714a48-2125-4ee7-b0bd-1df3fa329c77/ -- bulk88 ~ bulk88 at hotmail.com
RT-Send-CC: perl5-porters [...] perl.org
Download (untitled) / with headers
text/plain 2.1k
I think I found another report http://www.tek-tips.com/viewthread.cfm?qid=1231893 of the bug in this ticket, the bug being the mswsock!SockImportHandle calling vfbasics!AVrfpNtDeviceIoControlFile with a bad OS handle. On Server 2003, (not the NT 6 the OP is using), I tried a "closesocket(2);", 2 being a garbage handle. If WahReferenceContextByHandle in DSOCKET::GetCountedDSocketFromSocket returns 0, a tailcall is done to DSOCKET::FindIFSSocket from DSOCKET::GetCountedDSocketFromSocket. WahReferenceContextByHandle turns OS socket handles into user mode memory blocks/opaque pointers from the Winsock service provider. DSOCKET::FindIFSSocket starts doing syscalls on the bogus handle. The NtQueryObject correctly returns 0xC0000008/STATUS_INVALID_HANDLE for bogus handle "2". I've never used AppVerifier, but since Winsock will ALWAYS do syscalls on bogus handles that never were socket handles in the history of the process, AppVerifier will probably complain. The particular syscall/kernel call from winsock that generates the invalid handle exception, is very likely to change with each Windows OS, but it shows that there are detectable side effects from doing a closesocket on a bogus or disk OS handle. Show quoted text
> ntdll.dll!_NtQueryObject@20() + 0x7 bytes
kernel32.dll!_GetHandleInformation@8() + 0x5f bytes ws2_32.dll!DSOCKET::FindIFSSocket() + 0x1c bytes ws2_32.dll!_closesocket@4() + 0x2f bytes API.dll!@Call_asm@16() Line 100 Asm API.dll!XS_Win32__API_ImportCall(interpreter * my_perl=0x01d49840, cv * cv=0x00000004) Line 559 C perl519.dll!Perl_pp_entersub(interpreter * my_perl=0x00000000) Line 2764 C perl519.dll!Perl_runops_standard(interpreter * my_perl=0x01b64e74) Line 42 + 0x4 bytes C perl519.dll!S_run_body(interpreter * my_perl=0x00000000, long oldscope=1) Line 2500 + 0xa bytes C perl519.dll!perl_run(interpreter * my_perl=0x01b64e74) Line 2416 + 0x8 bytes C perl519.dll!RunPerl(int argc=5, char * * argv=0x01b64d68, char * * env=0x01b63800) Line 270 + 0x6 bytes C++ perl.exe!main(int argc=5, char * * argv=0x01b64d68, char * * env=0x01b63800) Line 23 + 0x12 bytes C perl.exe!__tmainCRTStartup() Line 582 + 0x17 bytes C kernel32.dll!_BaseProcessStart@4() + 0x28 bytes
RT-Send-CC: perl5-porters [...] perl.org
Download (untitled) / with headers
text/plain 1.8k
For the record, I can reproduce this, debugging blead perl in VC++ 2010 with AppVerifier running. My call stack is: ntdll.dll!77b1f921() [Frames below may be incorrect and/or missing, no symbols loaded for ntdll.dll] ntdll.dll!77b1f921() vfbasics.dll!50a936fa() mswsock.dll!73d76e77() vfbasics.dll!50a966d3() vfbasics.dll!50a966d3() Show quoted text
> perl519.dll!Perl_get_context() Line 32 C
perl519.dll!PerlIO_debug(const char * fmt, ...) Line 441 + 0x5 bytes C perl519.dll!win32_close(int fd) Line 3298 + 0x9 bytes C perl519.dll!PerlLIOClose(IPerlLIO * piPerl, int handle) Line 947 + 0x9 bytes C++ perl519.dll!PerlIOUnix_close(interpreter * my_perl, _PerlIO * * f) Line 2859 + 0x1c bytes C perl519.dll!PerlIOBase_close(interpreter * my_perl, _PerlIO * * f) Line 2200 + 0x10 bytes C perl519.dll!PerlIOBuf_close(interpreter * my_perl, _PerlIO * * f) Line 4230 + 0xd bytes C perl519.dll!PerlIO__close(interpreter * my_perl, _PerlIO * * f) Line 1457 + 0x10 bytes C perl519.dll!Perl_PerlIO_close(interpreter * my_perl, _PerlIO * * f) Line 1470 + 0xd bytes C perl519.dll!Perl_do_openn(interpreter * my_perl, gv * gv, const char * oname, long len, int as_raw, int rawmode, int rawperm, _PerlIO * * supplied_fp, sv * * svp, long num_svs) Line 674 + 0xd bytes C perl519.dll!Perl_pp_open(interpreter * my_perl) Line 640 + 0x2e bytes C perl519.dll!Perl_runops_debug(interpreter * my_perl) Line 2274 + 0xf bytes C perl519.dll!S_run_body(interpreter * my_perl, long oldscope) Line 2520 + 0xf bytes C perl519.dll!perl_run(interpreter * my_perl) Line 2439 C perl519.dll!RunPerl(int argc, char * * argv, char * * env) Line 270 + 0x9 bytes C++ perl.exe!main(int argc, char * * argv, char * * env) Line 23 + 0x12 bytes C perl.exe!__tmainCRTStartup() Line 555 + 0x17 bytes C kernel32.dll!7696336a() ntdll.dll!77b39f72() ntdll.dll!77b39f45()
RT-Send-CC: perl5-porters [...] perl.org
Download (untitled) / with headers
text/plain 309b
On Wed Oct 30 01:49:04 2013, shay wrote: Show quoted text
> For the record, I can reproduce this, debugging blead perl in VC++ > 2010 with AppVerifier running. My call stack is: >
I can also still reproduce this, with the same call stack, with the patch from #120091 (which is related but doesn't claim to fix this) applied.
RT-Send-CC: perl5-porters [...] perl.org
Download (untitled) / with headers
text/plain 7.5k
I'll add this here for archival reasons/google pickup. People using Procmon (MS/Sysinternals Process Monitor) on a Perl process, may sometimes see a couple calls in sequence to NtDeviceIOControlFile with IOCTL 0x12043. The exact line in procmon is "INVALID PARAMETER Control: 0x12043 (Device:0x1 Function:2064 Method: 3)" with a valid on disk file name the Path column (in most cases a .pm module). Do not be alarmed. 0x12043 is IOCTL_AFD_GET_CONTEXT. The C callstack that generates the failed 0x12043 is --------------------------------------------------------------------- Show quoted text
> ntdll.dll!_ZwDeviceIoControlFile@40()
mswsock.dll!_SockImportHandle@12() + 0xd2 bytes mswsock.dll!_SockFindAndReferenceSocket@8() + 0x430a bytes mswsock.dll!_WSPGetSockOpt@24() + 0x53 bytes ws2_32.dll!DCATALOG::FindIFSProviderForSocket() + 0xa4 bytes ws2_32.dll!DSOCKET::FindIFSSocket() + 0x37 bytes ws2_32.dll!_closesocket@4() + 0x2f bytes perl519.dll!my_close(int fd=0) Line 695 C perl519.dll!win32_close(int fd=4) Line 3301 + 0x9 bytes C perl519.dll!PerlLIOClose(IPerlLIO * piPerl=0x01c4817c, int handle=4) Line 947 + 0x9 bytes C++ perl519.dll!PerlIOUnix_close(interpreter * my_perl=0x01c45c54, _PerlIO * * f=0x00000000) Line 2859 + 0xb bytes C perl519.dll!PerlIOBase_close(interpreter * my_perl=0x01c45c54, _PerlIO * * f=0x01c66f24) Line 2200 + 0x8 bytes C perl519.dll!PerlIOBuf_close(interpreter * my_perl=0x01c45c54, _PerlIO * * f=0x01c66f24) Line 4231 C perl519.dll!Perl_PerlIO_close(interpreter * my_perl=0x01c45c54, _PerlIO * * f=0x01c66f24) Line 1470 + 0x24 bytes C perl519.dll!Perl_lex_next_chunk(interpreter * my_perl=0x01c45c54, unsigned long flags=2147483648) Line 1357 + 0x7 bytes C perl519.dll!Perl_yylex(interpreter * my_perl=0x01c45c54) Line 5344 + 0x7 bytes C perl519.dll!Perl_yyparse(interpreter * my_perl=0x01c45c54, int gramtype=258) Line 342 + 0x6 bytes C perl519.dll!S_doeval(interpreter * my_perl=0x00000000, int gimme=2, cv * outside=0x00000000, unsigned long seq=996, hv * hh=0x00000000) Line 3514 + 0x25 bytes C perl519.dll!Perl_pp_require(interpreter * my_perl=0x01c45c54) Line 4159 + 0x22 bytes C perl519.dll!Perl_runops_standard(interpreter * my_perl=0x01c45c54) Line 42 + 0x4 bytes C perl519.dll!S_run_body(interpreter * my_perl=0x00000000, long oldscope=1) Line 2433 + 0xa bytes C perl519.dll!perl_run(interpreter * my_perl=0x01c45c54) Line 2349 + 0x8 bytes C perl519.dll!RunPerl(int argc=3, char * * argv=0x01c45be8, char * * env=0x01c440e0) Line 270 + 0x6 bytes C++ perl.exe!__tmainCRTStartup() Line 582 + 0x17 bytes C kernel32.dll!_BaseProcessStart@4() + 0x28 bytes --------------------------------------------------------------------- Below is a sample from procmon on my machine of what the error looks like. I got alarmed seeing it, since IOCTLs on disk files are very very rare in procmon logs, so curiosity and a wonder if I have anti-security or pro-security software running on the machine made me investigate it. ----------------------------------------------------------------------- 9:25:30.3284509 PM perl.exe 21088 CreateFile C:\p519\src\lib\Errno.pm SUCCESS Desired Access: Generic Read, Disposition: Open, Options: Synchronous IO Non-Alert, Non-Directory File, Attributes: N, ShareMode: Read, Write, AllocationSize: n/a, OpenResult: Opened 9:25:30.3299015 PM perl.exe 21088 QueryInformationVolume C:\p519\src\lib\Errno.pm SUCCESS VolumeCreationTime: 5/26/2011 2:06:18 PM, VolumeSerialNumber: rmved, SupportsObjects: True, VolumeLabel: 9:25:30.3313223 PM perl.exe 21088 QueryAllInformationFile C:\p519\src\lib\Errno.pm BUFFER OVERFLOW CreationTime: 11/7/2013 4:49:58 PM, LastAccessTime: 11/7/2013 4:49:56 PM, LastWriteTime: 11/7/2013 4:49:58 PM, ChangeTime: 11/7/2013 4:49:58 PM, FileAttributes: RA, AllocationSize: 118,784, EndOfFile: 117,001, NumberOfLinks: 1, DeletePending: False, Directory: False, IndexNumber: 0x800000009b826, EaSize: 0, Access: Generic Read, Position: 0, Mode: Synchronous IO Non-Alert, AlignmentRequirement: Long 9:25:30.3332354 PM perl.exe 21088 ReadFile C:\p519\src\lib\Errno.pm SUCCESS Offset: 0, Length: 8,192 9:25:30.3359461 PM perl.exe 21088 ReadFile C:\p519\src\lib\Errno.pm SUCCESS Offset: 8,192, Length: 8,192 9:25:30.3380665 PM perl.exe 21088 ReadFile C:\p519\src\lib\Errno.pm SUCCESS Offset: 16,384, Length: 8,192 9:25:30.3400322 PM perl.exe 21088 ReadFile C:\p519\src\lib\Errno.pm SUCCESS Offset: 24,576, Length: 8,192 9:25:30.3420694 PM perl.exe 21088 ReadFile C:\p519\src\lib\Errno.pm SUCCESS Offset: 32,768, Length: 8,192 9:25:30.3440664 PM perl.exe 21088 ReadFile C:\p519\src\lib\Errno.pm SUCCESS Offset: 40,960, Length: 8,192 9:25:30.3459751 PM perl.exe 21088 ReadFile C:\p519\src\lib\Errno.pm SUCCESS Offset: 49,152, Length: 8,192 9:25:30.3479488 PM perl.exe 21088 ReadFile C:\p519\src\lib\Errno.pm SUCCESS Offset: 57,344, Length: 8,192 9:25:30.3498458 PM perl.exe 21088 ReadFile C:\p519\src\lib\Errno.pm SUCCESS Offset: 65,536, Length: 8,192 9:25:30.3519996 PM perl.exe 21088 ReadFile C:\p519\src\lib\Errno.pm SUCCESS Offset: 73,728, Length: 8,192 9:25:30.3540562 PM perl.exe 21088 ReadFile C:\p519\src\lib\Errno.pm SUCCESS Offset: 81,920, Length: 8,192 9:25:30.3563836 PM perl.exe 21088 ReadFile C:\p519\src\lib\Errno.pm SUCCESS Offset: 90,112, Length: 8,192 9:25:30.3587679 PM perl.exe 21088 ReadFile C:\p519\src\lib\Errno.pm SUCCESS Offset: 98,304, Length: 8,192 9:25:30.3610166 PM perl.exe 21088 ReadFile C:\p519\src\lib\Errno.pm SUCCESS Offset: 106,496, Length: 8,192 9:25:30.3722478 PM perl.exe 21088 ReadFile C:\p519\src\lib\Errno.pm SUCCESS Offset: 114,688, Length: 2,313 9:25:30.3754717 PM perl.exe 21088 DeviceIoControl C:\p519\src\lib\Errno.pm INVALID PARAMETER Control: 0x12043 (Device:0x1 Function:2064 Method: 3) 9:25:30.3783409 PM perl.exe 21088 DeviceIoControl C:\p519\src\lib\Errno.pm INVALID PARAMETER Control: 0x12043 (Device:0x1 Function:2064 Method: 3) 9:25:30.3811440 PM perl.exe 21088 DeviceIoControl C:\p519\src\lib\Errno.pm INVALID PARAMETER Control: 0x12043 (Device:0x1 Function:2064 Method: 3) 9:25:30.3840694 PM perl.exe 21088 DeviceIoControl C:\p519\src\lib\Errno.pm INVALID PARAMETER Control: 0x12043 (Device:0x1 Function:2064 Method: 3) 9:25:30.3868833 PM perl.exe 21088 DeviceIoControl C:\p519\src\lib\Errno.pm INVALID PARAMETER Control: 0x12043 (Device:0x1 Function:2064 Method: 3) 9:25:30.3882475 PM perl.exe 21088 CloseFile C:\p519\src\lib\Errno.pm SUCCESS ------------------------------------------------------- The "(Device:0x1 Function:2064 Method: 3)" is total garbage BTW. Device 1 (FILE_DEVICE_BEEP) is the system beeper. I dont hear beeps coming out of the machine. Something else is up. ---------------------------------- #define FILE_DEVICE_NETWORK 18 ..... #define FSCTL_AFD_BASE FILE_DEVICE_NETWORK #define _AFD_CONTROL_CODE(Operation,Method) \ ((FSCTL_AFD_BASE)<<12 | (Operation<<2) | Method) ...... #define AFD_GET_CONTEXT 16 ...... #define METHOD_NEITHER 3 ...... #define IOCTL_AFD_GET_CONTEXT \ _AFD_CONTROL_CODE(AFD_GET_CONTEXT, METHOD_NEITHER) ---------------------------------- ((18<<12)=0x12000, so ioctl call that starts with this is winsock related ---------------------------------- C:\Documents and Settings\Administrator>perl -e"printf('%x',((0x12<<12)|(0x10<<2 )|3)"); 12043 C:\Documents and Settings\Administrator> ---------------------------------- But the definition of IOCTL bitfield that MS and Promon use is different from winsock's _AFD_CONTROL_CODE #define CTL_CODE(DeviceType, Function, Method, Access) \ (((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method)) Once the ioctl code 0x12043 is decoded as a CTL_CODE it is "(Device:0x1 Function:2064 Method: 3)". -- bulk88 ~ bulk88 at hotmail.com
RT-Send-CC: perl5-porters [...] perl.org
Download (untitled) / with headers
text/plain 1.4k
On Wed Oct 30 02:08:09 2013, shay wrote: Show quoted text
> On Wed Oct 30 01:49:04 2013, shay wrote:
> > For the record, I can reproduce this, debugging blead perl in VC++ > > 2010 with AppVerifier running. My call stack is: > >
> > I can also still reproduce this, with the same call stack, with the > patch from #120091 (which is related but doesn't claim to fix this) > applied.
Posting a patch to this problem for comments/review. The idea is to tag sockets handles with a special low 2 bits pattern. The kernel ignores the last 2 bits of all handles, so the only meaning the low 2 bits have are on a user-mode (that includes kernel32.dll) level. 2 closesocket calls are necessary to avoid a leak in ws2_32.dll's socket descriptor to winsock provider vtable hash table. I'm not 100% sure that this won't create another race like #118059 fixed. This patch breaks non-IFS/non-kernel handle socket provider protocols even harder than before. Before=Perl already calls dup/dup2 on socket handles, which calls DuplicateHandle in the CRT, if the socket handle isn't a kernel handle (but a user mode pointer), that causes breakage. Also I assume Perl's sysread/syswrite/buffered IO calls also won't work on non-kernel socket handles, I think I've seen a ticket about that somewhere on RT before. Perl may have had support for doing recv instead of read() on sockets in the past, but I might be imagining it, will need to research. -- bulk88 ~ bulk88 at hotmail.com
Subject: 0001-WIP-don-t-closesocket-on-non-socket-handles.patch
From b431f923ee773478da393bb26dd45b07d1dbf7e8 Mon Sep 17 00:00:00 2001 From: Daniel Dragan <bulk88@hotmail.com> Date: Sat, 23 Nov 2013 17:03:32 -0500 Subject: [PATCH] WIP don't closesocket on non-socket handles --- win32/win32.c | 19 ++++++++++- win32/win32.h | 29 ++++++++++++++++++ win32/win32io.c | 5 ++- win32/win32sck.c | 86 ++++++++++++++++++++++++++++++++++------------------- 4 files changed, 105 insertions(+), 34 deletions(-) diff --git a/win32/win32.c b/win32/win32.c index fb24bbb..8a565d8 100644 --- a/win32/win32.c +++ b/win32/win32.c @@ -3332,13 +3332,28 @@ win32_isatty(int fd) DllExport int win32_dup(int fd) { - return dup(fd); + int ret; + int old = _osfhnd(fd); + //DebugBreak(); + ret = dup(fd); + if(ret != -1) { + int h = _osfhnd(ret); + assert(!SOCKET_FLAG_FROM_HANDLE(h)); + _osfhnd(ret) |= SOCKET_FLAG_FROM_HANDLE(_osfhnd(fd)); + } + return ret; } DllExport int win32_dup2(int fd1,int fd2) { - return dup2(fd1,fd2); + int ret = dup2(fd1,fd2); + if(ret != -1) { + int h = _osfhnd(fd2); + assert(!SOCKET_FLAG_FROM_HANDLE(h)); + _osfhnd(fd2) |= SOCKET_FLAG_FROM_HANDLE(_osfhnd(fd1)); + } + return ret; } DllExport int diff --git a/win32/win32.h b/win32/win32.h index a521a41..df51ffa 100644 --- a/win32/win32.h +++ b/win32/win32.h @@ -599,6 +599,35 @@ EXTERN_C _CRTIMP ioinfo* __pioinfo[]; /* since we are not doing a dup2(), this works fine */ # define _set_osfhnd(fh, osfh) (void)(_osfhnd(fh) = (intptr_t)osfh) + +/* derived from IsConsoleHandle macro, (((ULONG_PTR)(h) & 0x10000003) == 0x3) + if low 2 bits are 11, then its a console psuedo handle that only Win32 + subsystem understands, not a kernel handle, a kernel handle ends in 00, we + reserve 10 to mean socket handle, starting in Windows 8 according to reports + online, console handles are kernel handles, low 2 bits behaviour on Win8 + consone handles is unresearched, 0x80000000 catches negative values are + other psuedo handles or invalid handle, meaning behind flag 0x10000000 is + unknown, 01 can not be used since 01 handles are listed as FILE_TYPE_UNKNOWN, + and the handle is not passed to a kernel call to determine its type, this + causes _fstati64 to fail, making open() from PP fail when opening a numeric + fd that contains 01 tagged handle +*/ + +//static void +//PerlIOUnix_setfd(pTHX_ PerlIO *f, int fd, int imode) +//{ +// PerlIOUnix * const s = PerlIOSelf(f, PerlIOUnix); +//#if defined(WIN32) +// Stat_t st; +// if (PerlLIO_fstat(fd, &st) == 0) { <<<<< calls GetFileType in CRT which makes fstat fail +// +# define HANDLE_IS_SCK 0x2 +# define PSUEDO_HANDLES_MASK 0x90000003 +# define IS_PSUEDO_HANDLE(h) ((ULONG_PTR)(h) & PSUEDO_HANDLES_MASK) +# define SOCKET_FLAG_FROM_HANDLE(h) ((IS_PSUEDO_HANDLE(h) == HANDLE_IS_SCK) ? HANDLE_IS_SCK : 0x0) +/* slow, and does failing kernel calls, use only in DEBUGGING */ +# define PUBLIC_IS_SOCKET(h) (GetFileType(h) == FILE_TYPE_PIPE && GetNamedPipeInfo(h, 0, 0, 0, 0) == 0) + #endif /* PERL_CORE */ /* IO.xs and POSIX.xs define PERLIO_NOT_STDIO to 1 */ diff --git a/win32/win32io.c b/win32/win32io.c index d183e3b..817628e 100644 --- a/win32/win32io.c +++ b/win32/win32io.c @@ -321,7 +321,10 @@ PerlIOWin32_dup(pTHX_ PerlIO *f, PerlIO *o, CLONE_PARAMS *params, int flags) if (DuplicateHandle(proc, os->h, proc, &new_h, 0, FALSE, DUPLICATE_SAME_ACCESS)) { char mode[8]; - int fd = win32_open_osfhandle((intptr_t) new_h, PerlIOUnix_oflags(PerlIO_modestr(o,mode))); + int fd; + assert(!(SOCKET_FLAG_FROM_HANDLE(new_h) || IS_PSUEDO_HANDLE(new_h))); + *((ULONG_PTR *)&new_h) |= SOCKET_FLAG_FROM_HANDLE(os->h); + fd = win32_open_osfhandle((intptr_t) new_h, PerlIOUnix_oflags(PerlIO_modestr(o,mode))); if (fd >= 0) { f = PerlIOBase_dup(aTHX_ f, o, params, flags); diff --git a/win32/win32sck.c b/win32/win32sck.c index 674add2..df92946 100644 --- a/win32/win32sck.c +++ b/win32/win32sck.c @@ -396,7 +396,11 @@ win32_accept(SOCKET s, struct sockaddr *addr, int *addrlen) SOCKET r; SOCKET_TEST((r = accept(TO_SOCKET(s), addr, addrlen)), INVALID_SOCKET); - return OPEN_SOCKET(r); + assert(!(SOCKET_FLAG_FROM_HANDLE(r) || IS_PSUEDO_HANDLE(r))); + r = OPEN_SOCKET(r); + if( r != -1) + _osfhnd(r) |= HANDLE_IS_SCK; + return r; } int @@ -670,8 +674,13 @@ win32_socket(int af, int type, int protocol) if((s = open_ifs_socket(af, type, protocol)) == INVALID_SOCKET) errno = get_last_socket_error(); - else + else { + assert(!(SOCKET_FLAG_FROM_HANDLE(s) || IS_PSUEDO_HANDLE(s))); + /* _open_osfhandle does a GetFileType which bans handles ending in 01 */ s = OPEN_SOCKET(s); + if( s != -1) + _osfhnd(s) |= HANDLE_IS_SCK; + } return s; } @@ -690,21 +699,28 @@ int my_close(int fd) return(close(fd)); /* Then not a socket. */ osf = TO_SOCKET(fd);/* Get it now before it's gone! */ if (osf != -1) { - int err; - err = closesocket(osf); - if (err == 0) { - assert(_osfhnd(fd) == osf); /* catch a bad ioinfo struct def */ - /* don't close freed handle */ - _set_osfhnd(fd, INVALID_HANDLE_VALUE); - return close(fd); + if(SOCKET_FLAG_FROM_HANDLE(osf)) { + int err = closesocket(osf); + int err2 = closesocket(osf&~HANDLE_IS_SCK); + assert(err == err2); /* ???? */ + if (err == 0) { + assert(_osfhnd(fd) == osf); /* catch a bad ioinfo struct def */ + /* don't close freed handle */ + _set_osfhnd(fd, INVALID_HANDLE_VALUE); + return close(fd); + } + else if (err == SOCKET_ERROR) { + err = get_last_socket_error(); + assert(err != ENOTSOCK); + /* note this does a not allowed by MS CloseHandle + on the socket handle */ + (void)close(fd); + errno = err; + return EOF; + } } - else if (err == SOCKET_ERROR) { - err = get_last_socket_error(); - if (err != ENOTSOCK) { - (void)close(fd); - errno = err; - return EOF; - } + else { + assert(!PUBLIC_IS_SOCKET(osf)); } } return close(fd); @@ -721,21 +737,29 @@ my_fclose (FILE *pf) if (osf != -1) { int err; win32_fflush(pf); - err = closesocket(osf); - if (err == 0) { - assert(_osfhnd(win32_fileno(pf)) == osf); /* catch a bad ioinfo struct def */ - /* don't close freed handle */ - _set_osfhnd(win32_fileno(pf), INVALID_HANDLE_VALUE); - return fclose(pf); - } - else if (err == SOCKET_ERROR) { - err = get_last_socket_error(); - if (err != ENOTSOCK) { - (void)fclose(pf); - errno = err; - return EOF; - } - } + if(SOCKET_FLAG_FROM_HANDLE(osf)) { + int err = closesocket(osf); + int err2 = closesocket(osf&~HANDLE_IS_SCK); + assert(err == err2); /* ???? */ + if (err == 0) { + assert(_osfhnd(win32_fileno(pf)) == osf); /* catch a bad ioinfo struct def */ + /* don't close freed handle */ + _set_osfhnd(win32_fileno(pf), INVALID_HANDLE_VALUE); + return fclose(pf); + } + else if (err == SOCKET_ERROR) { + err = get_last_socket_error(); + assert(err != ENOTSOCK); + /* note this does a not allowed by MS CloseHandle + on the socket handle */ + (void)fclose(pf); + errno = err; + return EOF; + } + } + else { + assert(!PUBLIC_IS_SOCKET(osf)); + } } return fclose(pf); } -- 1.7.9.msysgit.0
RT-Send-CC: perl5-porters [...] perl.org
Download (untitled) / with headers
text/plain 1.1k
On Sat Nov 23 14:16:48 2013, bulk88 wrote: Show quoted text
> > Posting a patch to this problem for comments/review. The idea is to > tag sockets handles with a special low 2 bits pattern. The kernel > ignores the last 2 bits of all handles, so the only meaning the low 2 > bits have are on a user-mode (that includes kernel32.dll) level. 2 > closesocket calls are necessary to avoid a leak in ws2_32.dll's socket > descriptor to winsock provider vtable hash table. I'm not 100% sure > that this won't create another race like #118059 fixed. This patch > breaks non-IFS/non-kernel handle socket provider protocols even harder > than before. Before=Perl already calls dup/dup2 on socket handles, > which calls DuplicateHandle in the CRT, if the socket handle isn't a > kernel handle (but a user mode pointer), that causes breakage. Also I > assume Perl's sysread/syswrite/buffered IO calls also won't work on > non-kernel socket handles, I think I've seen a ticket about that > somewhere on RT before. Perl may have had support for doing recv > instead of read() on sockets in the past, but I might be imagining it, > will need to research. >
Bump. -- bulk88 ~ bulk88 at hotmail.com
RT-Send-CC: perl5-porters [...] perl.org
Download (untitled) / with headers
text/plain 132b
This ticket needs "Operating System" to be changed to "mswin32". I dont have the perms to do it. -- bulk88 ~ bulk88 at hotmail.com
From: Karl Williamson <public [...] khwilliamson.com>
Date: Sun, 22 Dec 2013 21:10:02 -0700
Subject: Re: [perl #118127] Perl crash when run under AppVerifier
To: perlbug-followup [...] perl.org, "OtherRecipients of perl Ticket #118127:;" [...] smtp.indra.com
CC: perl5-porters [...] perl.org
Download (untitled) / with headers
text/plain 152b
On 12/22/2013 08:42 PM, bulk88 via RT wrote: Show quoted text
> This ticket needs "Operating System" to be changed to "mswin32". I dont have the perms to do it. >
Done
RT-Send-CC: perl5-porters [...] perl.org
Download (untitled) / with headers
text/plain 1.2k
On Sun Dec 22 19:40:08 2013, bulk88 wrote: Show quoted text
> On Sat Nov 23 14:16:48 2013, bulk88 wrote:
> > > > Posting a patch to this problem for comments/review. The idea is to > > tag sockets handles with a special low 2 bits pattern. The kernel > > ignores the last 2 bits of all handles, so the only meaning the low 2 > > bits have are on a user-mode (that includes kernel32.dll) level. 2 > > closesocket calls are necessary to avoid a leak in ws2_32.dll's socket > > descriptor to winsock provider vtable hash table. I'm not 100% sure > > that this won't create another race like #118059 fixed. This patch > > breaks non-IFS/non-kernel handle socket provider protocols even harder > > than before. Before=Perl already calls dup/dup2 on socket handles, > > which calls DuplicateHandle in the CRT, if the socket handle isn't a > > kernel handle (but a user mode pointer), that causes breakage. Also I > > assume Perl's sysread/syswrite/buffered IO calls also won't work on > > non-kernel socket handles, I think I've seen a ticket about that > > somewhere on RT before. Perl may have had support for doing recv > > instead of read() on sockets in the past, but I might be imagining it, > > will need to research. > >
> > Bump.
Bump. -- bulk88 ~ bulk88 at hotmail.com
RT-Send-CC: perl5-porters [...] perl.org
Download (untitled) / with headers
text/plain 1.5k
On Sat Nov 23 14:16:48 2013, bulk88 wrote: Show quoted text
> Posting a patch to this problem for comments/review. The idea is to > tag sockets handles with a special low 2 bits pattern. The kernel > ignores the last 2 bits of all handles, so the only meaning the low 2 > bits have are on a user-mode (that includes kernel32.dll) level. 2 > closesocket calls are necessary to avoid a leak in ws2_32.dll's socket > descriptor to winsock provider vtable hash table. I'm not 100% sure > that this won't create another race like #118059 fixed. This patch > breaks non-IFS/non-kernel handle socket provider protocols even harder > than before. Before=Perl already calls dup/dup2 on socket handles, > which calls DuplicateHandle in the CRT, if the socket handle isn't a > kernel handle (but a user mode pointer), that causes breakage. Also I > assume Perl's sysread/syswrite/buffered IO calls also won't work on > non-kernel socket handles, I think I've seen a ticket about that > somewhere on RT before. Perl may have had support for doing recv > instead of read() on sockets in the past, but I might be imagining it, > will need to research. >
What is the breakage caused to non-IFS providers that you refer to? I'm wondering what effect it will have on previous changes in this area: 036c1c1eb7 - Fix [perl #24269] socket() call uses non-IFS providers causing subsequent print/read to hang or misbehave 1c97260979 - Implement new environment variable to allow the use of non-IFS compatible LSP's on Windows to allow Perl to work in conjunction with a firewall such as McAfee Guardian
RT-Send-CC: perl5-porters [...] perl.org
Download (untitled) / with headers
text/plain 2.1k
On Mon Jan 27 10:12:36 2014, shay wrote: Show quoted text
> On Sat Nov 23 14:16:48 2013, bulk88 wrote:
> > Posting a patch to this problem for comments/review. The idea is to > > tag sockets handles with a special low 2 bits pattern. The kernel > > ignores the last 2 bits of all handles, so the only meaning the low 2 > > bits have are on a user-mode (that includes kernel32.dll) level. 2 > > closesocket calls are necessary to avoid a leak in ws2_32.dll's > > socket > > descriptor to winsock provider vtable hash table. I'm not 100% sure > > that this won't create another race like #118059 fixed. This patch > > breaks non-IFS/non-kernel handle socket provider protocols even > > harder > > than before. Before=Perl already calls dup/dup2 on socket handles, > > which calls DuplicateHandle in the CRT, if the socket handle isn't a > > kernel handle (but a user mode pointer), that causes breakage. Also I > > assume Perl's sysread/syswrite/buffered IO calls also won't work on > > non-kernel socket handles, I think I've seen a ticket about that > > somewhere on RT before. Perl may have had support for doing recv > > instead of read() on sockets in the past, but I might be imagining > > it, > > will need to research. > >
> > What is the breakage caused to non-IFS providers that you refer to? > I'm wondering what effect it will have on previous changes in this > area: > > 036c1c1eb7 - Fix [perl #24269] socket() call uses non-IFS providers > causing subsequent print/read to hang or misbehave
That seems to have prohibited non-IFS protocols if I read it correctly, since if the protocol doesn't have "XP1_IFS_HANDLES" a socket using that protocol can't be created. The OP in 24269 is unclear, but he refers to sockets and kernel IO operations like WriteFile, and kernel I/O handle scheduling. He says "SO_SYNCHRONOUS_NONALERT" but i think he meant WSA_FLAG_OVERLAPPED. Show quoted text
> > 1c97260979 - Implement new environment variable to allow the use of > non-IFS compatible LSP's on Windows to allow Perl to work in > conjunction with a firewall such as McAfee Guardian
That creates an option to removal the prohibition of non-IFS protocols. -- bulk88 ~ bulk88 at hotmail.com
RT-Send-CC: perl5-porters [...] perl.org
Download (untitled) / with headers
text/plain 153b
On Wed Mar 05 05:05:34 2014, bulk88 wrote: Show quoted text
> On Mon Jan 27 10:12:36 2014, shay wrote:
Bump. Steve Hay? Tony C? JDB? -- bulk88 ~ bulk88 at hotmail.com
RT-Send-CC: perl5-porters [...] perl.org
Download (untitled) / with headers
text/plain 142b
On Sat Nov 23 14:16:48 2013, bulk88 wrote: Show quoted text
> The kernel > ignores the last 2 bits of all handles,
Do Microsoft document that anywhere? Tony
RT-Send-CC: perl5-porters [...] perl.org
Download (untitled) / with headers
text/plain 3.2k
On Wed Jul 08 22:45:47 2015, tonyc wrote: Show quoted text
> On Sat Nov 23 14:16:48 2013, bulk88 wrote:
> > The kernel > > ignores the last 2 bits of all handles,
> > Do Microsoft document that anywhere? > > Tony
http://blogs.msdn.com/b/oldnewthing/archive/2008/08/27/8898863.aspx http://blogs.msdn.com/b/oldnewthing/archive/2005/01/21/358109.aspx From MS headers ----------------------------------------------------------------- #define STDAPI EXTERN_C HRESULT STDAPICALLTYPE #define STDAPI_(type) EXTERN_C type STDAPICALLTYPE #define STDMETHODIMP HRESULT STDMETHODCALLTYPE #define STDMETHODIMP_(type) type STDMETHODCALLTYPE // The 'V' versions allow Variable Argument lists. #define STDAPIV EXTERN_C HRESULT STDAPIVCALLTYPE #define STDAPIV_(type) EXTERN_C type STDAPIVCALLTYPE #define STDMETHODIMPV HRESULT STDMETHODVCALLTYPE #define STDMETHODIMPV_(type) type STDMETHODVCALLTYPE // end_winnt // // Low order two bits of a handle are ignored by the system and available // for use by application code as tag bits. The remaining bits are opaque // and used to store a serial number and table index. // #define OBJ_HANDLE_TAGBITS 0x00000003L // // Cardinal Data Types [0 - 2**N-2) // typedef char CCHAR; // winnt typedef short CSHORT; typedef ULONG CLONG; typedef CCHAR *PCCHAR; typedef CSHORT *PCSHORT; typedef CLONG *PCLONG; // end_ntminiport end_ntndis end_ntminitape ------------------------------------------------------------------ Reactos code http://doxygen.reactos.org/d0/d54/ntdef_8h_source.html#l01577 use of low 2 bits to store CWD directory handle inside Kernel32/ntdll http://doxygen.reactos.org/d9/d6e/lib_2rtl_2path_8c_source.html#l00026 reactos defintion of a kernel handle ----------------------------------------------------------------- 00054 typedef union _EXHANDLE 00055 { 00056 struct 00057 { 00058 ULONG_PTR TagBits:2; 00059 ULONG_PTR Index:29; 00060 }; 00061 struct 00062 { 00063 ULONG_PTR TagBits2:2; 00064 ULONG_PTR LowIndex:HANDLE_LOW_BITS; 00065 ULONG_PTR MidIndex:HANDLE_HIGH_BITS; 00066 ULONG_PTR HighIndex:HANDLE_HIGH_BITS; 00067 ULONG_PTR KernelFlag:KERNEL_FLAG_BITS; 00068 }; 00069 HANDLE GenericHandleOverlay; 00070 ULONG_PTR Value; 00071 } EXHANDLE, *PEXHANDLE; 00072 ---------------------------------------------------- http://doxygen.reactos.org/de/d51/ntoskrnl_2ex_2handle_8c_source.html#l00045 at line 45 the low 2 bits are cleared when converting a handle to a kernel pointer ---------------------------------------------------- MS's version -----------cut------------------- PHANDLE_TABLE_ENTRY ExpLookupHandleTableEntry ( IN PHANDLE_TABLE HandleTable, IN EXHANDLE tHandle ) { -----------cut------------------- EXHANDLE Handle; -----------cut------------------- ULONG_PTR MaxHandle; -----------cut------------------- // // Extract the handle index // Handle = tHandle; Handle.TagBits = 0; MaxHandle = *(volatile ULONG *) &HandleTable->NextHandleNeedingPool; ---------------------------------- It is obvious I will have to rebase and clean up the commit a bit more before it can be applied. -- bulk88 ~ bulk88 at hotmail.com
RT-Send-CC: perl5-porters [...] perl.org
On Thu Jul 09 04:10:20 2015, bulk88 wrote: Show quoted text
> On Wed Jul 08 22:45:47 2015, tonyc wrote:
> > On Sat Nov 23 14:16:48 2013, bulk88 wrote:
> > > The kernel > > > ignores the last 2 bits of all handles,
> > > > Do Microsoft document that anywhere?
> > http://blogs.msdn.com/b/oldnewthing/archive/2008/08/27/8898863.aspx > http://blogs.msdn.com/b/oldnewthing/archive/2005/01/21/358109.aspx
As we discussed in IRC, my main concern was whether the sockets returned by socket() were also kernel handles and had those reserved bits. From our discussion, I think we can reasonably assume that for, whether some badly written anti-virus or firewall we can only find out in the real world. As also discussed, duplicating a socket with your patch produces a handle that we have flagged as a socket, but since the CRT dup() function just does a DuplicateHandle() winsock doesn't think it's a socket and fails to close it. If some external C code decides to dup() the fd without the mapping in XSUB.h visible, this will also produce a bad fd, but there's not really anything we can do about it. Tony
RT-Send-CC: perl5-porters [...] perl.org
Download (untitled) / with headers
text/plain 11.9k
On Sun Jul 12 19:14:04 2015, tonyc wrote: Show quoted text
> As we discussed in IRC, my main concern was whether the sockets > returned > by socket() were also kernel handles and had those reserved bits.
Perl would act very bizarre and flawed if diamond operator failed on sockets that got fdreopened/duped. Also, I dont think that win32_accept or win32_socket would even return a "fd" for a user mode socket. The SOCKET */maybe handle is turned into a fd with OPEN_SOCKET/win32_open_osfhandle/_open_osfhandle. _open_osfhandle calls GetFileType, if GetFileType fails/returns FILE_TYPE_UNKNOWN (same val), MS CRT wont alloc a fd. GetFileType is mostly a wrapper around NtQueryVolumeInformationFile, which obviously requires a real kernel handle. ---------------------------------------------------------- int __cdecl _open_osfhandle( intptr_t osfhandle, int flags ) { int fh; char fileflags; /* _osfile flags */ DWORD isdev; /* device indicator in low byte */ /* copy relevant flags from second parameter */ ...........cut..................... /* find out what type of file (file/device/pipe) */ isdev = GetFileType((HANDLE)osfhandle); if (isdev == FILE_TYPE_UNKNOWN) { /* OS error */ _dosmaperr( GetLastError() ); /* map error */ return -1; } ---------------------------------------------------------- Perl internally has IoTYPE_SOCKET flag but I am not sure if reopening a fd preserves IoTYPE_SOCKET flag or not, and if there is adequate testing of the flag (and how to see the flag from PP without B::/Devel::Peek). http://perl5.git.perl.org/perl.git/commitdiff/036c1c1eb70a0dfc5a7187959eb5e39d499c9396 and http://perl5.git.perl.org/perl.git/commitdiff/1c97260979b979af03b946d71d50e8e4c075665c would basically have to go away, possibly replaced with panics in win32_accept and win32_socket (the only 2 ways to make a socket, correct me if I am wrong) if the low 2 bits are not 0. There is also the problem, that assuming a SOCKET * is a memory addr instead of kernel handle, the low 2 bits will be zero because that private C struct behind the SOCKET * is going to be aligned to atleast 4 bytes if not 8 or 16, so low 2 bits being zero can't separate a mem addr socket from a handle socket. So maybe either the open_ifs_socket/WSCEnumProtocols/XP1_IFS_HANDLES code stays, or GetHandleInformation has to be used to figure out if its a kernel handle socket. There is a slightly remote remote (should I round it to impossible?) chance that a mem addr might be a valid handle if over ~350K handles have been allocated. Windows can not allocate VM below addr 0x00010000 and on my system most handles are between 0x100 and 0x1000, and 0x2000 at tops. I'll skip the details (nobody wants a tour of Win32 VM layout), so the first possible malloc address is 0x150000. 0x150000/4=0x54000=344064 kernel handles. http://blogs.technet.com/b/markrussinovich/archive/2009/09/29/3283844.aspx says the limit is 16 million handles. So a [perl] process with mem addr SOCKETs, plus a large handle leak, could wind up mem addr socket pointers that are valid kernel handles, although the failure in this case would be that the panic croak of GetHandleInformation stops being thrown and GetHandleInformation returns true, is a kernel handle, even though the number is really a user mode SOCKET * and not a handle, and by coincidence, user mode SOCKET * happens to be a handle (maybe a file, maybe a mutex, maybe a process). But talking about deciding if its a user mode SOCKET or a kernel handle SOCKET and supporting user mode sockets is all in vain if _open_osfhandle will never allocate a fd for a user mode socket. User mode sockets aren't inheritable http://stackoverflow.com/questions/11847793/are-tcp-socket-handles-inheritable Show quoted text
> > From our discussion, I think we can reasonably assume that for, > whether some > badly written anti-virus or firewall we can only find out in the real > world.
Would anyone still use such a firewall in the 2010s? How many non-perl apps (php/python/ruby/non interpretated lang progs) would be broken if sockets aren't kernel handles? Now lets see what other engines do about closesocket vs close/CloseHandle on Win32. http://caml.inria.fr/mantis/view.php?id=5258 ocaml remembers what is a file and what is a socket CPYTHON cpython doesn't use _open_osfhandle on sockets, sockets are not fds https://docs.python.org/2/library/socket.html " Note that there are no methods read() or write(); use recv() and send() without flags argument instead. ------------------------ socket.fileno() Return the socket’s file descriptor (a small integer). This is useful with select.select(). Under Windows the small integer returned by this method cannot be used where a file descriptor can be used (such as os.fdopen()). Unix does not have this limitation. " https://github.com/python/cpython/blob/master/Modules/socketmodule.c the "fd/fileno" is the SOCKET */kernel handle, no _open_osfhandle https://github.com/python/cpython/blob/master/Modules/posixmodule.c#L8484 only use of _open_osfhandle that isn't on stderr/stdout/stdin in cpython https://github.com/python/cpython/blob/master/Lib/multiprocessing/connection.py#L354 socket object knows its a socket and not a fd on win32 PHP https://github.com/php/php-src/blob/master/ext/sockets/windows_common.h#L34 https://github.com/php/php-src/blob/master/ext/sockets/sockets.c#L492 http://php.net/manual/en/book.sockets.php sockets are socket objects/class, they know they aren't fds on Win32, no fileno method, no _open_osfhandle "fastcgi" knows if its a socket or not https://github.com/php/php-src/blob/PHP-5.6.11/sapi/cgi/fastcgi.c#L756 https://github.com/php/php-src/blob/PHP-5.6.11/sapi/cgi/fastcgi.c#L1112 RUBY https://github.com/ruby/ruby/blob/trunk/win32/win32.c#L7374 https://github.com/ruby/ruby/blob/trunk/win32/win32.c#L6025 https://github.com/ruby/ruby/blob/trunk/win32/win32.c#L2425 https://github.com/ruby/ruby/blob/trunk/win32/win32.c#L713 Ruby in a separate table remembers what handles are sockets. That is an analog of using Perl's ptr_table_fetch https://github.com/ruby/ruby/blob/trunk/st.c#L383 Also Ruby does not use _open_osfhandle the way Perl does https://github.com/ruby/ruby/blob/trunk/win32/win32.c#L2353 instead ruby creates a dummy handle, then swaps handles in ioinfo struct that backs the CRT's fd. I wonder why, https://github.com/ruby/ruby/commit/92e4b1b06e10557e1cfce4962b55f4960f6ed5b5 not very explaining. In designing the handle tagging patch, 01 tagged handles fail GetFileType that _open_osfhandle does internally, which causes _open_osfhandle to fail. By calling CRT _open_osfhandle with a dummy valid handle, then swaping handles in the CRT struct, you could stick user mode sockets in there that fail GetFileType (not sure if that is useful). Show quoted text
> As also discussed, duplicating a socket with your patch produces a > handle > that we have flagged as a socket, but since the CRT dup() function > just > does a DuplicateHandle() winsock doesn't think it's a socket and fails > to > close it.
The attached patch tries fix that by comparing the error codes from closesocket on the original and tagged handles. if (errtagged == erruntagged) /* this catches WSAENOTSOCK */ err = erruntagged; else if (errtagged != WSAENOTSOCK && erruntagged == WSAENOTSOCK) err = errtagged; else if (errtagged == WSAENOTSOCK && erruntagged != WSAENOTSOCK) err = erruntagged; else DebugBreak(); /* 2 different states, which to pass to caller ??? */ If both closesockets return errors that are not WSAENOTSOCK, which error code is passed up to the caller from perl's my_close? IDK what it should be. Always the untagged version? which is the older/original handle. There is also a little bit of reservations I have, since this patch increases the memory that each socket takes up by one extra DSOCKET object in ws2_32.dll (0x18 bytes long), and 0xd8 bytes inside mswsock.dll at this callstack ntdll.dll!_RtlAllocateHeap@12() + 0xf mswsock.dll!_SockImportHandle@8() + 0x199 mswsock.dll!_SockFindAndReferenceSocket@8() + 0x90a9 mswsock.dll!_WSPGetSockOpt@24() + 0x54 ws2_32.dll!DCATALOG::FindIFSProviderForSocket() + 0x95 ws2_32.dll!DSOCKET::FindIFSSocket() + 0x37 ws2_32.dll!_closesocket@4() + 0x2f perl523.dll!my_close(int fd=4) Line 719 + 0x9 C perl523.dll!PerlLIOClose(IPerlLIO * piPerl=0x00365b8c, int handle=4) Line 944 + 0x9 C perl523.dll!PerlIOUnix_close(interpreter * my_perl=0x00363efc, _PerlIO * * f=0x00000000) Line 2804 + 0xb C perl523.dll!PerlIOBase_close(interpreter * my_perl=0x00363efc, _PerlIO * * f=0x008f568c) Line 2120 + 0x8 C perl523.dll!PerlIOBuf_close(interpreter * my_perl=0x00363efc, _PerlIO * * f=0x008f568c) Line 4229 C perl523.dll!PerlIO__close(interpreter * my_perl=0x00363efc, _PerlIO * * f=0xfffffffe) Line 1382 + 0x7 C perl523.dll!Perl_PerlIO_close(interpreter * my_perl=0x00363efc, _PerlIO * * f=0x008f568c) Line 1395 + 0x10 C perl523.dll!Perl_io_close(interpreter * my_perl=0x00000000, io * io=0x71a871e0, gv * gv=0x00000000, char not_implicit=0, char warn_on_fail=0) Line 1091 + 0x9 C perl523.dll!Perl_sv_clear(interpreter * my_perl=0x00363efc, sv * const orig_sv=0x0093c92c) Line 6443 + 0x25 C perl523.dll!Perl_sv_free2(interpreter * my_perl=0x00363efc, sv * const sv=0x0093c92c, const unsigned long rc=1) Line 6885 C perl523.dll!S_SvREFCNT_dec_NN(interpreter * my_perl=0x00363efc, sv * sv=0xfffffffe) Line 177 + 0xb C perl523.dll!do_clean_named_io_objs(interpreter * my_perl=0x00363efc, sv * const sv=0x00921f6c) Line 625 + 0x6 C perl523.dll!S_visit(interpreter * my_perl=0x00363efc, void (interpreter *, sv *)* f=0x2809033b, const unsigned long flags=32777, const unsigned long mask=49407) Line 502 C perl523.dll!Perl_sv_clean_objs(interpreter * my_perl=0x00000000) Line 660 C perl523.dll!perl_destruct(interpreter * my_perl=0x00363efc) Line 804 C perl523.dll!RunPerl(int argc=3, char * * argv=0x01363de8, char * * env=0x00362f38) Line 263 C perl.exe!mainCRTStartup() Line 398 + 0xe C kernel32.dll!_BaseProcessStart@4() + 0x23 There is also the CPU overhead of the "importing", but currently when perl is closesocket'ing disk files and pipes once winsock has been loaded/started to be used in the process, the "importing" is happening but failing. The ideal solution would be to get IoTYPE_SOCKET down to unix layer, and have unix layer pass it onto my_close_maybe_a_socket. perl523.dll!PerlIOUnix_open(interpreter * my_perl=0x00363efc, _PerlIO_funcs * self=0x280f86c0, PerlIO_list_s * layers=0x008f547c, long n=0, const char * mode=0x2814fbd4, int fd=3, int imode=0, int perm=0, _PerlIO * * f=0x00000000, int narg=0, sv * * args=0x00000000) Line 2668 C perl523.dll!PerlIOBuf_open(interpreter * my_perl=0x00363efc, _PerlIO_funcs * self=0x280f8880, PerlIO_list_s * layers=0x008f547c, long n=1, const char * mode=0x2814fbd4, int fd=3, int imode=0, int perm=0, _PerlIO * * f=0x00000000, int narg=0, sv * * args=0x00000000) Line 3858 + 0x1b C perl523.dll!PerlIO_openn(interpreter * my_perl=0x00363efc, const char * layers=0x00000000, const char * mode=0x2814fbd4, int fd=3, int imode=0, int perm=0, _PerlIO * * f=0x00000000, int narg=0, sv * * args=0x00000000) Line 1561 + 0x1d C perl523.dll!PerlIO_fdopen(int fd=3, const char * mode=0x2814fbd4) Line 4886 + 0x16 C perl523.dll!Perl_pp_socket(interpreter * my_perl=0x00000006) Line 2484 C perl523.dll!Perl_runops_standard(interpreter * my_perl=0x00363efc) Line 41 + 0x4 C perl523.dll!S_run_body(interpreter * my_perl=0x00000000, long oldscope=1) Line 2448 + 0xa C perl523.dll!perl_run(interpreter * my_perl=0x00363efc) Line 2371 + 0x8 C perl523.dll!RunPerl(int argc=3, char * * argv=0x01363de8, char * * env=0x00362f38) Line 258 + 0x6 C perl.exe!mainCRTStartup() Line 398 + 0xe C kernel32.dll!_BaseProcessStart@4() + 0x23 mode arg shows + mode 0x2814fbd4 "rb" const char * for me, not "s" or "rs" "b" is #define PIPESOCK_MODE "b" /* pipes, sockets default to binmode */ -- bulk88 ~ bulk88 at hotmail.com
Subject: 0001-WIP-118127-don-t-closesocket-on-non-socket-handles-o.patch
From 04461bd1387d842e9c6d431e1ed9e9927631c198 Mon Sep 17 00:00:00 2001 From: Daniel Dragan <bulk88@hotmail.com> Date: Tue, 21 Jul 2015 02:48:44 -0400 Subject: [PATCH] WIP #118127 don't closesocket on non-socket handles on Win32 -win32io.c changes due to win32io.c(336) : error C2296: '|=' : illegal, left operand has type 'HANDLE' --- inline.h | 10 ++++ win32/win32.c | 32 +++++++++++++- win32/win32.h | 44 +++++++++++++++++++ win32/win32io.c | 7 +++- win32/win32sck.c | 122 ++++++++++++++++++++++++++++++++++++++++-------------- 5 files changed, 181 insertions(+), 34 deletions(-) diff --git a/inline.h b/inline.h index 46a8cb6..3e99e96 100644 --- a/inline.h +++ b/inline.h @@ -350,6 +350,16 @@ S_should_warn_nl(const char *pv) { #endif +/* ------------------ win32sck.c ------------ */ + +#if defined(WIN32) && !defined(WIN32_NO_SOCKETS) +PERL_STATIC_INLINE BOOL +S_is_handle_valid(HANDLE hnd) { + DWORD dwFlags; + return GetHandleInformation(hnd, &dwFlags); +} +#endif + /* ------------------ pp.c, regcomp.c, toke.c, universal.c ------------ */ #define MAX_CHARSET_NAME_LENGTH 2 diff --git a/win32/win32.c b/win32/win32.c index 1ec045e..211db9f 100644 --- a/win32/win32.c +++ b/win32/win32.c @@ -3328,13 +3328,41 @@ win32_isatty(int fd) DllExport int win32_dup(int fd) { - return dup(fd); + int ret; + ret = dup(fd); +#ifndef WIN32_NO_SOCKETS + if(ret != -1) { + int old_h = _osfhnd(fd); + int flag = SOCKET_FLAG_FROM_HANDLE(old_h); + int new_h = _osfhnd(ret); + assert(!SOCKET_FLAG_FROM_HANDLE(new_h) + && PUBLIC_IS_SOCKET(new_h) == PUBLIC_IS_SOCKET(old_h)); + new_h |= flag; + _osfhnd(ret) = new_h; + } +#endif + return ret; } DllExport int win32_dup2(int fd1,int fd2) { - return dup2(fd1,fd2); + int ret; + ret = dup2(fd1,fd2); +#ifndef WIN32_NO_SOCKETS + if(ret != -1) { + /* assert(!SOCKET_FLAG_FROM_HANDLE(_osfhnd(fd2))); + _osfhnd(fd2) |= SOCKET_FLAG_FROM_HANDLE(_osfhnd(fd1)); */ + int old_h = _osfhnd(fd1); + int flag = SOCKET_FLAG_FROM_HANDLE(old_h); + int new_h = _osfhnd(fd2); + assert(!SOCKET_FLAG_FROM_HANDLE(new_h) + && PUBLIC_IS_SOCKET(new_h) == PUBLIC_IS_SOCKET(old_h)); + new_h |= flag; + _osfhnd(fd2) = new_h; + } +#endif + return ret; } DllExport int diff --git a/win32/win32.h b/win32/win32.h index 3b35b6c..5d90839 100644 --- a/win32/win32.h +++ b/win32/win32.h @@ -625,6 +625,50 @@ EXTERN_C _CRTIMP ioinfo* __pioinfo[]; /* since we are not doing a dup2(), this works fine */ # define _set_osfhnd(fh, osfh) (void)(_osfhnd(fh) = (intptr_t)osfh) + +/* derived from IsConsoleHandle macro, (((ULONG_PTR)(h) & 0x10000003) == 0x3) + if low 2 bits are 11, then its a console psuedo handle that only Win32 + subsystem understands, not a kernel handle, a kernel handle ends in 00, we + reserve 10 to mean socket handle, starting in Windows 8 according to reports + online, console handles are kernel handles, low 2 bits behaviour on Win8 + consone handles is unresearched, 0x80000000 catches negative values are + other psuedo handles (STD_INPUT_HANDLE/-10/STD_OUTPUT_HANDLE/-11) or invalid + handle (-1), meaning behind flag 0x10000000 is unknown, 01 can not be used + since 01 handles are special cased to fail by GetFileType, + and the handle is not passed to a kernel call to determine its type, this + causes _fstati64 to fail, making open() from PP fail when opening a numeric + fd that contains 01 tagged handle, thus leaving 10 as the only permutation + that can be used. +*/ + +/* +static void +PerlIOUnix_setfd(pTHX_ PerlIO *f, int fd, int imode) +{ + PerlIOUnix * const s = PerlIOSelf(f, PerlIOUnix); +#if defined(WIN32) + Stat_t st; + if (PerlLIO_fstat(fd, &st) == 0) { <<<<< calls GetFileType in CRT which makes fstat fail +*/ + +# ifndef WIN32_NO_SOCKETS +# define HANDLE_IS_SCK 0x2 +# define PSUEDO_HANDLES_MASK 0x90000003 +# define IS_PSUEDO_HANDLE(h) ((ULONG_PTR)(h) & PSUEDO_HANDLES_MASK) +# define SOCKET_FLAG_FROM_HANDLE(h) ((IS_PSUEDO_HANDLE(h) == HANDLE_IS_SCK) ? HANDLE_IS_SCK : 0x0) +/* [use] public [api to find out if the handle] is [a] socket + + Slow, and does failing kernel calls, use only in DEBUGGING, not for regular builds. + There is no simple way to find out what is a socket, since the NT drivers for + named pipes (NPFS) and TCPIP (AFD or ws2ifsl) both call themselves + FILE_TYPE_PIPE/FILE_DEVICE_NAMED_PIPE. GetNamedPipeInfo internally is an + named pipe driver only ioctl. If the handle/driver sucessfully responds to a + NPFS ioctl, it proves that the handle is a pipe. Else it is assumed (but it + can't be proven without doing a winsock call) to be a socket. +*/ +# define PUBLIC_IS_SOCKET(h) (GetFileType((HANDLE)h) == FILE_TYPE_PIPE \ + && GetNamedPipeInfo((HANDLE)h, 0, 0, 0, 0) == 0) +# endif #endif /* PERL_CORE */ /* IO.xs and POSIX.xs define PERLIO_NOT_STDIO to 1 */ diff --git a/win32/win32io.c b/win32/win32io.c index 00f5bb8..7f06f28 100644 --- a/win32/win32io.c +++ b/win32/win32io.c @@ -329,7 +329,12 @@ PerlIOWin32_dup(pTHX_ PerlIO *f, PerlIO *o, CLONE_PARAMS *params, int flags) if (DuplicateHandle(proc, os->h, proc, &new_h, 0, FALSE, DUPLICATE_SAME_ACCESS)) { char mode[8]; - int fd = win32_open_osfhandle((intptr_t) new_h, PerlIOUnix_oflags(PerlIO_modestr(o,mode))); + int fd; +#ifndef WIN32_NO_SOCKETS + assert(!(SOCKET_FLAG_FROM_HANDLE(new_h) || IS_PSUEDO_HANDLE(new_h))); + *((ULONG_PTR *)&new_h) |= SOCKET_FLAG_FROM_HANDLE(os->h); +#endif + fd = win32_open_osfhandle((intptr_t) new_h, PerlIOUnix_oflags(PerlIO_modestr(o,mode))); if (fd >= 0) { f = PerlIOBase_dup(aTHX_ f, o, params, flags); diff --git a/win32/win32sck.c b/win32/win32sck.c index 3f97241..07bda9f 100644 --- a/win32/win32sck.c +++ b/win32/win32sck.c @@ -396,7 +396,14 @@ win32_accept(SOCKET s, struct sockaddr *addr, int *addrlen) SOCKET r; SOCKET_TEST((r = accept(TO_SOCKET(s), addr, addrlen)), INVALID_SOCKET); - return OPEN_SOCKET(r); +#ifndef WIN32_NO_SOCKETS + assert(!(SOCKET_FLAG_FROM_HANDLE(r) || IS_PSUEDO_HANDLE(r))); + if (r != INVALID_SOCKET) + r |= HANDLE_IS_SCK; +#endif + /* why is this call creating a fd for an invalud socket ??? */ + r = OPEN_SOCKET(r); + return r; } int @@ -619,6 +626,15 @@ open_ifs_socket(int af, int type, int protocol) int error_code; SOCKET out = INVALID_SOCKET; +/* looking all this up on every socket call is stupid, + everything (including the convert_proto_info_w2a calls, should use WSASocketW instead) + but the for loop needs to be factored out into StartSockets, assuming this + code from Winsock 1 era isn't completly removed + + https://rt.perl.org/Ticket/Display.html?id=24269 + + http://perl5.git.perl.org/perl.git/commitdiff/036c1c1eb70a0dfc5a7187959eb5e39d499c9396 + */ if ((s = PerlEnv_getenv("PERL_ALLOW_NON_IFS_LSP")) && atoi(s)) return WSASocket(af, type, protocol, NULL, 0, 0); @@ -661,6 +677,8 @@ open_ifs_socket(int af, int type, int protocol) return out; } +#ifndef WIN32_NO_SOCKETS + SOCKET win32_socket(int af, int type, int protocol) { @@ -670,8 +688,12 @@ win32_socket(int af, int type, int protocol) if((s = open_ifs_socket(af, type, protocol)) == INVALID_SOCKET) errno = get_last_socket_error(); - else + else { + assert(!(SOCKET_FLAG_FROM_HANDLE(s) || IS_PSUEDO_HANDLE(s))); + if (s != INVALID_SOCKET) + s |= HANDLE_IS_SCK; s = OPEN_SOCKET(s); + } return s; } @@ -683,6 +705,7 @@ win32_socket(int af, int type, int protocol) * -- BKS, 11-11-2000 */ + int my_close(int fd) { int osf; @@ -690,22 +713,49 @@ int my_close(int fd) return(close(fd)); /* Then not a socket. */ osf = TO_SOCKET(fd);/* Get it now before it's gone! */ if (osf != -1) { - int err; - err = closesocket(osf); - if (err == 0) { - assert(_osfhnd(fd) == osf); /* catch a bad ioinfo struct def */ - /* don't close freed handle */ - _set_osfhnd(fd, INVALID_HANDLE_VALUE); - return close(fd); - } - else if (err == SOCKET_ERROR) { - err = get_last_socket_error(); - if (err != ENOTSOCK) { + if(SOCKET_FLAG_FROM_HANDLE(osf)) { + int err; + int osftagged = osf; + int errtagged = closesocket(osftagged) == SOCKET_ERROR ? WSAGetLastError() : ERROR_SUCCESS; + int osfuntagged = osftagged &~ HANDLE_IS_SCK; + int erruntagged = closesocket(osfuntagged) == SOCKET_ERROR ? WSAGetLastError() : ERROR_SUCCESS; +/* use Socket; socket(SOCK, PF_INET, SOCK_STREAM, getprotobyname(\"tcp\")); +open(SOCKTWO, '<&' . fileno(SOCK)); close(SOCKTWO); +this code sample uses dup/DuplicateHandle and creates a tagged handle, +that is never once passed to a socket function, until the 1st closesocket, and then +the 2nd closesocket fails with WSAENOTSOCK since winsock front end never got a func call on the untagged handle before, and attempting to vivify/"Import" the untagged handle fails, since the socket was closed in the WSP layer/mswsock.dll/afd.sys in the 1st closesocket, and on the 2nd closesocket, WSP layer/mswsock.dll/afd.sys does not tell the front end "yes I created this handle/socket" + +Therefore, only if tagged and untagged both return WSAENOTSOCK, will the result be WSAENOTSOCK, else the result of the operation will be something other than WSAENOTSOCK +*/ + /* both kernel handles should be dead by now */ + assert(!S_is_handle_valid((HANDLE)osfuntagged) + && !S_is_handle_valid((HANDLE)osftagged)); + if (errtagged == erruntagged) /* this catches WSAENOTSOCK */ + err = erruntagged; + else if (errtagged != WSAENOTSOCK && erruntagged == WSAENOTSOCK) + err = errtagged; + else if (errtagged == WSAENOTSOCK && erruntagged != WSAENOTSOCK) + err = erruntagged; + else + DebugBreak(); /* 2 different states, which to pass to caller ??? */ + if (err == ERROR_SUCCESS) { + assert(_osfhnd(fd) == osftagged); /* catch a bad ioinfo struct def */ + /* don't close freed handle */ + _set_osfhnd(fd, INVALID_HANDLE_VALUE); + return close(fd); + } + else { + assert(err != ENOTSOCK); + /* note close() does a not allowed by MS CloseHandle + on the socket handle */ (void)close(fd); - errno = err; + errno = convert_wsa_error_to_errno(err); return EOF; } } + else { + assert(!PUBLIC_IS_SOCKET(osf)); + } } return close(fd); } @@ -715,30 +765,40 @@ int my_fclose (FILE *pf) { int osf; + int fd; if (!wsock_started) /* No WinSock? */ return(fclose(pf)); /* Then not a socket. */ - osf = TO_SOCKET(win32_fileno(pf));/* Get it now before it's gone! */ + osf = TO_SOCKET(fd = win32_fileno(pf));/* Get it now before it's gone! */ if (osf != -1) { - int err; win32_fflush(pf); - err = closesocket(osf); - if (err == 0) { - assert(_osfhnd(win32_fileno(pf)) == osf); /* catch a bad ioinfo struct def */ - /* don't close freed handle */ - _set_osfhnd(win32_fileno(pf), INVALID_HANDLE_VALUE); - return fclose(pf); - } - else if (err == SOCKET_ERROR) { - err = get_last_socket_error(); - if (err != ENOTSOCK) { - (void)fclose(pf); - errno = err; - return EOF; - } - } + if(SOCKET_FLAG_FROM_HANDLE(osf)) { + /* this code does not match my_close ATM, my_close is authoritative */ + int err = closesocket(osf); + int err2 = closesocket(osf&~HANDLE_IS_SCK); + assert(err == err2); /* ???? */ + if (err == 0) { + assert(_osfhnd(fd) == osf); /* catch a bad ioinfo struct def */ + /* don't close freed handle */ + _set_osfhnd(fd, INVALID_HANDLE_VALUE); + return fclose(pf); + } + else if (err == SOCKET_ERROR) { + err = get_last_socket_error(); + assert(err != ENOTSOCK); + /* note this does a not allowed by MS CloseHandle + on the socket handle */ + (void)fclose(pf); + errno = err; + return EOF; + } + } + else { + assert(!PUBLIC_IS_SOCKET(osf)); + } } return fclose(pf); } +#endif /* #ifndef WIN32_NO_SOCKETS */ struct hostent * win32_gethostbyaddr(const char *addr, int len, int type) -- 1.7.9.msysgit.0


This service is sponsored and maintained by Best Practical Solutions and runs on Perl.org infrastructure.

For issues related to this RT instance (aka "perlbug"), please contact perlbug-admin at perl.org