From: "cfis (Charlie Savage) via ruby-core" Date: 2025-11-19T17:31:34+00:00 Subject: [ruby-core:123862] [Ruby Bug#21498] Windows - Ruby Overrides C Library APIs thus breaking them Issue #21498 has been updated by cfis (Charlie Savage). Hi YO4 - thank you for your last comment - I appreciate it. I too need to strive for better communication, because clearly I am not communicating very well. I hope we can all assume the best intentions in others, and realize communication, especially online, in tickets and with cultural differences is difficult. I think your comment shows where we are not communicating: > I still don't understand how calls to overridden functions that are using the original routine could cause problems in a healthy setup. If the Ruby shared library on windows did not include this line in its DEF file - `fclose=rb_w32_fclose` - then the extension would use `fclose` from its debug version of the UCRT and not Ruby's release build of UCRT. Thus the problem is solved, at least in this one case. Second, by "healthy setup" I think you mean that Ruby and all extensions share the same UCRT. I think that is the best case, and likely true 99% of the time, but I am trying to explore if that restriction is absolutely necessary. Because in real life sometimes UCRT's are mismatched (static builds with UCRT, debug builds, before UCRT different C runtimes per MSVC version). Which is why I keep coming back to the same question - does Ruby still need to export (or as I have said above overrides) these function today? Ruby has done amazing work providing a consistent API across platforms, and windows is quite different that other operating systems. Your example of networking and winsock are excellent ones - those clearly are needed to be standardized across operating systems and it makes sense for Ruby to for example export `select`. So I am only discussing the exports that override URCT: > access=rb_w32_uaccess > close=rb_w32_close > dup2=rb_w32_dup2 > fclose=rb_w32_fclose > fstat=rb_w32_fstati128 (_fstat) > get_osfhandle=rb_w32_get_osfhandle (_get_osfhandle) > getpid=rb_w32_getpid > isatty=rb_w32_isatty > lseek=rb_w32_lseek > mkdir=rb_w32_umkdir > pipe=rb_w32_pipe (_pipe) > read=rb_w32_read > rename=rb_w32_urename > rmdir=rb_w32_urmdir > strerror=rb_w32_strerror > unlink=rb_w32_uunlink I hope that clarifies why I think this is an issue worth of discussion and resolution? I did propose a concrete path forward that I hoped would address your concerns (see if we can use a debug build to catch these errors). Do you think that is worth pursuing? ---------------------------------------- Bug #21498: Windows - Ruby Overrides C Library APIs thus breaking them https://bugs.ruby-lang.org/issues/21498#change-115260 * 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/