Issue #21498 has been updated by YO4 (Yoshinao Muramatsu). The discussion you cited seemed to me to be ignoring the actual problem by pinning the cause solely on ruby's behavior. You used it to solidify your argument within the ruby community, and even tried to borrow Microsoft's authority to do so. That's how I felt about it. No need to apologize, but we must always keep learning. I still don't understand how calls to overridden functions that are using the original routine could cause problems in a healthy setup. What do you mean 'the problems introduced by the ucrt functions that are overridden'? I don't know what the difficulties faced by the OpenStudio people actually stemmed from, since they haven't provided that information. However, I can examine the OpenStudio-3.1 binaries of that time. ```
objdump -p openstudio.so | grep "DLL Name" DLL Name: openstudiolib.dll DLL Name: x64-msvcrt-ruby250.dll DLL Name: USER32.dll DLL Name: KERNEL32.dll DLL Name: MSVCP140.dll DLL Name: VCRUNTIME140.dll DLL Name: VCRUNTIME140_1.dll DLL Name: api-ms-win-crt-runtime-l1-1-0.dll DLL Name: api-ms-win-crt-stdio-l1-1-0.dll DLL Name: api-ms-win-crt-heap-l1-1-0.dll DLL Name: api-ms-win-crt-string-l1-1-0.dll DLL Name: api-ms-win-crt-time-l1-1-0.dll
I should note that even back then, it was possible to build ruby using ucrt with msvc.
Lets move on to the technical details.
I've already mentioned that ruby has C-level cross-platform support.
For example, winsock library lacks support for errno, but ruby's wrapper makes it usable.
File and socket fds can be handled uniformly on other operating systems, but on windows, you must use _close() and closesocket() appropriately depending on the target.
This is what ruby is currently tackling.
Should we allow selecting whether to include overrides during build time?
The moment we do, we'll be flooded with reports of mysterious errors here and to gem developers. Maybe Windows-specific error reports will flood useful gem developers using other OSes, even though their code is correct.
Furthermore, setup differences could make troubleshooting difficult. I don't want to see a future where gem developers come to hate the Windows platform.
If you continue to propose overriding deletions, I believe you need to provide an alternative solution.
If removing the override made the test pass, then the test is likely insufficient.
As mentioned above, it works fine on other operating systems. They don't need that test.
It's no secret that the Windows version has platform-specific issues and relies on community contributions. We can contribute as well.
The debug version of the Microsoft C runtime library is not redistributable. That is to say, the user is the developer.
What I meant by "user" is that you are responsible for matching the C runtime DLL in this case.
I don't want to burden the ruby core team any further.
My apologies, but the basis for your argument in this issue has been lost, and I believe continuing discussion here would be unproductive.
If you have a better solutions to what ruby is currently doing, or if you have made progress in your own efforts, they would be welcome.
I apologize for the lengthy message.
Regards
----------------------------------------
Bug #21498: Windows - Ruby Overrides C Library APIs thus breaking them
https://bugs.ruby-lang.org/issues/21498#change-115245
* Author: cfis (Charlie Savage)
* Status: Open
* Assignee: windows
* ruby -v: *all* on windows (testing with ruby 3.4.3 (2025-04-14 revision d0b7e5b6a0) +PRISM [x64-mswin64_140])
* Backport: 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN
----------------------------------------
I am trying to wrap a simple C++ library, https://github.com/baderouaich/BitmapPlusPlus, as a Ruby extension.
However when I use the extension to write a bitmap to disk the bitmap is corrupted. This is because the library uses std::ofstream which eventually uses the C API fclose to write the final bytes to the bitmap file and then closes it. The problem is that Ruby overrides `fclose` and replaces it with `rb_w32_fclose`. It then *exports* its custom version from from x64-vcruntime140-ruby340.dll. And the exported version is broken (at least from the standpoint of the C standard library).
Note this has been a long standing issue. The first report I see is from 2013:
https://bugs.ruby-lang.org/issues/8569
More recently in 2020 (which explains the issue very well):
https://github.com/NREL/OpenStudio/issues/3942#issuecomment-610673401
I understand that Ruby is trying to provide a platform independent API. But the problem is this solution breaks any third party libraries that rely on these C APIs (which of course are very common). And there is no good workaround (see https://github.com/NREL/OpenStudio/issues/3942#issuecomment-611072774).
So would it be possible for Ruby to stop exporting custom versions of basic C APIs? The code that does it is here:
https://github.com/ruby/ruby/blob/master/win32/mkexports.rb#L41
Ruby of course could still use its custom versions of `fclose`, read, write etc within ruby.exe and x64-vcruntime140-ruby340.dll. But they should not be exported from x64-vcruntime140-ruby340.dll and thus be off limits to extensions. If a case comes up where an extension really needs access to rb_w32_fclose instead of fclose then an extension developer can use an `#ifdef _WIN32` to do so and work across platforms. That at least puts the developer in control versus now where I don't see any way I can wrap the bitmap library as a Ruby extension.
From my experience the biggest problem is the replacing of fclose with rb_w32_fclose.
This is the list of generated overrides:
FD_CLR=rb_w32_fdclr
FD_ISSET=rb_w32_fdisset
Sleep=rb_w32_Sleep
accept=rb_w32_accept
access=rb_w32_uaccess
bind=rb_w32_bind
close=rb_w32_close
connect=rb_w32_connect
dup2=rb_w32_dup2
fclose=rb_w32_fclose
fstat=rb_w32_fstati128
get_osfhandle=rb_w32_get_osfhandle
getcwd=rb_w32_ugetcwd
getenv=rb_w32_ugetenv
gethostbyaddr=rb_w32_gethostbyaddr
gethostbyname=rb_w32_gethostbyname
gethostname=rb_w32_gethostname
getpeername=rb_w32_getpeername
getpid=rb_w32_getpid
getppid=rb_w32_getppid
getprotobyname=rb_w32_getprotobyname
getprotobynumber=rb_w32_getprotobynumber
getservbyname=rb_w32_getservbyname
getservbyport=rb_w32_getservbyport
getsockname=rb_w32_getsockname
getsockopt=rb_w32_getsockopt
inet_ntop=rb_w32_inet_ntop
inet_pton=rb_w32_inet_pton
ioctlsocket=rb_w32_ioctlsocket
isatty=rb_w32_isatty
listen=rb_w32_listen
lseek=rb_w32_lseek
lstat=rb_w32_ulstati128
mkdir=rb_w32_umkdir
mmap=rb_w32_mmap
mprotect=rb_w32_mprotect
munmap=rb_w32_munmap
pipe=rb_w32_pipe
pread=rb_w32_pread
pwrite=rb_w32_pwrite
read=rb_w32_read
recv=rb_w32_recv
recvfrom=rb_w32_recvfrom
rename=rb_w32_urename
rmdir=rb_w32_urmdir
select=rb_w32_select
send=rb_w32_send
sendto=rb_w32_sendto
setsockopt=rb_w32_setsockopt
shutdown=rb_w32_shutdown
socket=rb_w32_socket
stati128=rb_w32_ustati128
strcasecmp=msvcrt.stricmp
strerror=rb_w32_strerror
strncasecmp=msvcrt.strnicmp
times=rb_w32_times
unlink=rb_w32_uunlink
utime=rb_w32_uutime
utimensat=rb_w32_uutimensat
utimes=rb_w32_uutimes
write=rb_w32_write
---Files--------------------------------
Screenshot 2025-11-06 233918.png (223 KB)
primitives.bmp (360 KB)
primitives_bad.bmp (360 KB)
--
https://bugs.ruby-lang.org/