Skip to content

Fix memory leak if sk_push fails#1009

Merged
rhenium merged 1 commit intoruby:masterfrom
ndossche:clesss-1
Feb 26, 2026
Merged

Fix memory leak if sk_push fails#1009
rhenium merged 1 commit intoruby:masterfrom
ndossche:clesss-1

Conversation

@ndossche
Copy link
Contributor

If it fails, then the duplicated item is not freed. Solve it by making sure the push cannot fail by reserving the necessary stack size upfront.

Example Valgrind trace:

14,009 (384 direct, 13,625 indirect) bytes in 1 blocks are definitely lost in loss record 27,287 of 27,373
  malloc (at /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
  CRYPTO_zalloc (at /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
  <unknown stack frame>
  ASN1_item_new (at /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
 *ossl_x509_alloc (ossl_x509cert.c:97)
  <unknown stack frame>
  rb_class_new_instance_pass_kw (at /usr/lib/x86_64-linux-gnu/libruby-3.2.so.3.2.3)
  <unknown stack frame>
  <unknown stack frame>
  <unknown stack frame>
  <unknown stack frame>
  rb_vm_exec (at /usr/lib/x86_64-linux-gnu/libruby-3.2.so.3.2.3)
  <unknown stack frame>
  <unknown stack frame>
  rb_catch_obj (at /usr/lib/x86_64-linux-gnu/libruby-3.2.so.3.2.3)
  <unknown stack frame>
  <unknown stack frame>
  <unknown stack frame>
  rb_vm_exec (at /usr/lib/x86_64-linux-gnu/libruby-3.2.so.3.2.3)
  rb_yield (at /usr/lib/x86_64-linux-gnu/libruby-3.2.so.3.2.3)
  rb_ary_each (at /usr/lib/x86_64-linux-gnu/libruby-3.2.so.3.2.3)
  <unknown stack frame>
  <unknown stack frame>
  <unknown stack frame>
  rb_vm_exec (at /usr/lib/x86_64-linux-gnu/libruby-3.2.so.3.2.3)
  rb_yield (at /usr/lib/x86_64-linux-gnu/libruby-3.2.so.3.2.3)
  rb_ary_each (at /usr/lib/x86_64-linux-gnu/libruby-3.2.so.3.2.3)
  <unknown stack frame>
  <unknown stack frame>
  <unknown stack frame>
  rb_vm_exec (at /usr/lib/x86_64-linux-gnu/libruby-3.2.so.3.2.3)
  rb_yield (at /usr/lib/x86_64-linux-gnu/libruby-3.2.so.3.2.3)
  rb_ary_each (at /usr/lib/x86_64-linux-gnu/libruby-3.2.so.3.2.3)
  <unknown stack frame>
  <unknown stack frame>
  <unknown stack frame>
  rb_vm_exec (at /usr/lib/x86_64-linux-gnu/libruby-3.2.so.3.2.3)
  rb_yield (at /usr/lib/x86_64-linux-gnu/libruby-3.2.so.3.2.3)
  rb_ary_each (at /usr/lib/x86_64-linux-gnu/libruby-3.2.so.3.2.3)
  <unknown stack frame>
  <unknown stack frame>
  <unknown stack frame>
  rb_vm_exec (at /usr/lib/x86_64-linux-gnu/libruby-3.2.so.3.2.3)
  <unknown stack frame>
  <unknown stack frame>
  rb_catch_obj (at /usr/lib/x86_64-linux-gnu/libruby-3.2.so.3.2.3)
  <unknown stack frame>
  <unknown stack frame>
  <unknown stack frame>
  rb_vm_exec (at /usr/lib/x86_64-linux-gnu/libruby-3.2.so.3.2.3)

This was found by a hybrid static-dynamic analyser that looks for inconsistent handling of error checks in bindings.

@ndossche
Copy link
Contributor Author

Unfortunately because of libressl we cannot use new_reserve and therefore need to check the return value of the push...

If it fails, then the duplicated item is not freed.
Solve it by making sure the push cannot fail by reserving the necessary
stack size upfront.

Example Valgrind trace:
```
14,009 (384 direct, 13,625 indirect) bytes in 1 blocks are definitely lost in loss record 27,287 of 27,373
  malloc (at /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
  CRYPTO_zalloc (at /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
  <unknown stack frame>
  ASN1_item_new (at /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
 *ossl_x509_alloc (ossl_x509cert.c:97)
  <unknown stack frame>
  rb_class_new_instance_pass_kw (at /usr/lib/x86_64-linux-gnu/libruby-3.2.so.3.2.3)
  <unknown stack frame>
  <unknown stack frame>
  <unknown stack frame>
  <unknown stack frame>
  rb_vm_exec (at /usr/lib/x86_64-linux-gnu/libruby-3.2.so.3.2.3)
  <unknown stack frame>
  <unknown stack frame>
  rb_catch_obj (at /usr/lib/x86_64-linux-gnu/libruby-3.2.so.3.2.3)
  <unknown stack frame>
  <unknown stack frame>
  <unknown stack frame>
  rb_vm_exec (at /usr/lib/x86_64-linux-gnu/libruby-3.2.so.3.2.3)
  rb_yield (at /usr/lib/x86_64-linux-gnu/libruby-3.2.so.3.2.3)
  rb_ary_each (at /usr/lib/x86_64-linux-gnu/libruby-3.2.so.3.2.3)
  <unknown stack frame>
  <unknown stack frame>
  <unknown stack frame>
  rb_vm_exec (at /usr/lib/x86_64-linux-gnu/libruby-3.2.so.3.2.3)
  rb_yield (at /usr/lib/x86_64-linux-gnu/libruby-3.2.so.3.2.3)
  rb_ary_each (at /usr/lib/x86_64-linux-gnu/libruby-3.2.so.3.2.3)
  <unknown stack frame>
  <unknown stack frame>
  <unknown stack frame>
  rb_vm_exec (at /usr/lib/x86_64-linux-gnu/libruby-3.2.so.3.2.3)
  rb_yield (at /usr/lib/x86_64-linux-gnu/libruby-3.2.so.3.2.3)
  rb_ary_each (at /usr/lib/x86_64-linux-gnu/libruby-3.2.so.3.2.3)
  <unknown stack frame>
  <unknown stack frame>
  <unknown stack frame>
  rb_vm_exec (at /usr/lib/x86_64-linux-gnu/libruby-3.2.so.3.2.3)
  rb_yield (at /usr/lib/x86_64-linux-gnu/libruby-3.2.so.3.2.3)
  rb_ary_each (at /usr/lib/x86_64-linux-gnu/libruby-3.2.so.3.2.3)
  <unknown stack frame>
  <unknown stack frame>
  <unknown stack frame>
  rb_vm_exec (at /usr/lib/x86_64-linux-gnu/libruby-3.2.so.3.2.3)
  <unknown stack frame>
  <unknown stack frame>
  rb_catch_obj (at /usr/lib/x86_64-linux-gnu/libruby-3.2.so.3.2.3)
  <unknown stack frame>
  <unknown stack frame>
  <unknown stack frame>
  rb_vm_exec (at /usr/lib/x86_64-linux-gnu/libruby-3.2.so.3.2.3)
```
@rhenium
Copy link
Member

rhenium commented Feb 26, 2026

I've squashed in the fixup commit.

Copy link
Member

@rhenium rhenium left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! Thanks for spotting.

@rhenium rhenium merged commit 1c4bfef into ruby:master Feb 26, 2026
47 of 48 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants