From: "YO4 (Yoshinao Muramatsu) via ruby-core" Date: 2025-11-18T12:35:48+00:00 Subject: [ruby-core:123847] [Ruby Bug#21498] Windows - Ruby Overrides C Library APIs thus breaking them 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/ ______________________________________________ ruby-core mailing list -- ruby-core@ml.ruby-lang.org To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/