Repository navigation
Conversation
nogvl_cleanup raised the first SQL Server error before it freed the malloc'd nonblocking_errors array. Each error leaked the array (4,136 bytes). Copy the errors into a Ruby-managed buffer. Free the array before any raise.
5 tasks done
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
nogvl_cleanupraises the first SQL Server error withrb_exc_raise. A raise from C is alongjmp: it leaves the function at once. Thus thefree(userdata->nonblocking_errors)call after the loop does not run.nogvl_setupallocates this array withmallocforERRORS_STACK_INIT_SIZEerrors. The array is 4,136 bytes on 64-bit Linux. Each query that fails leaks one array, because the nextnogvl_setupcall replaces the pointer.Fix
ALLOCV_N).mallocarray and reset its fields.If the message handler or the raise leaves the function, the GC frees the copy. The order of the messages does not change. The raised exception does not change.
Measurements
The tool is ruby_memcheck 3.0.1. It runs Ruby under Valgrind and removes the false positives that Ruby causes. A "definitely lost" block is a block with no pointer to it at exit.
masterOn
master, 15 more failing queries add 62,040 bytes. That is 4,136 bytes for each error. With this PR, the total stays the same for any number of errors. The 32,879 bytes that remain come from the one-timedbinitallocations (the FreeTDS context).Reproduction script
Validation
bundle exec rake test: 123 tests, 535 assertions, 0 failures, 0 errors.binary_name: "tiny_tds") shows no invalid read or write, and no leak fromnogvl_setup. The remaining leaks come from failed logins. Raise login errors after dbopen returns #614 fixes them.astyle --options=astyle.confdoes not change the C files.Environment: Ruby 4.0.7 on Linux aarch64, FreeTDS 1.5.19 built from source, SQL Server 2022 CU27 (
mcr.microsoft.com/mssql/server:2022-latest), Valgrind 3.24.0.Note
The draft
v4branch (#603) movesnogvl_cleanuptoclient.cwith the same body. That branch has the same leak.