Skip to content

Memory leak in convert when conversion fails #91

Description

@grgalex

Problem

In convert, the memory allocated [1] through calloc() for the output data is never freed (or realloc()'d) when the conversion fails.

We further confirmed the memory leak by using Google's Address Sanitizer [2].

Steps to reproduce

  1. Build from source with the following env. variables set:

    • export CXXFLAGS='-fsanitize=address'
    • export LDFLAGS='-fsanitize=address'
  2. Find location of libasan.so (the location on your system may differ)

$ gcc -print-file-name=libasan.so

/usr/lib/gcc/x86_64-linux-gnu/12/libasan.so
  1. Create a file named test.cjs with the following contents
x = require('./build/Debug/addon.node')

y = Buffer.alloc(2 ** 32, 0xFF)


for (let i = 0; i < 10; i++) {
    try {
        x.convert(y)
    } catch (err) {}
}
  1. Run with:
LD_PRELOAD=<path from step (2)> node test.cjs
  1. Output reports 40GiB (= 10 * 2^32), i.e., 10 times the size of the Buffer we passed to convert.
Parsing of the input font failed.
Parsing of the input font failed.
Parsing of the input font failed.
Parsing of the input font failed.                                              
Parsing of the input font failed.                                              
Parsing of the input font failed.                                              
Parsing of the input font failed.                                              
Parsing of the input font failed.                                              
Parsing of the input font failed.                                              
Parsing of the input font failed.                                              

=================================================================                                                                                             
==1069469==ERROR: LeakSanitizer: detected memory leaks                                                                                                        

Direct leak of 42949683200 byte(s) in 10 object(s) allocated from:                                                                                            
#0 0x7f332525b3b7 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:77
#1 0x7f33208a40fd in convert(Nan::FunctionCallbackInfo<v8::Value> const&) ../csrc/addon.cc:27
#2 0x7f33208a0f54 in FunctionCallbackWrapper ../../nan/nan_callbacks_12_inl.h:177
#3 0x561ed7b92aa1  (<unknown module>)
<...snip...>
#15 0x561f36c18907 in v8::internal::GeneratedCode<unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, long, unsigned long**>::Call(unsigned long, unsigned long, unsigned long, unsigned long, long, unsigned long**) ../deps/v8/src/execution/simulator.h:178
#16 0x561f36c18907 in Invoke ../deps/v8/src/execution/execution.cc:417
#17 0x63100001526f  (<unknown module>)

SUMMARY: AddressSanitizer: 42949683200 byte(s) leaked in 10 allocation(s).

[1] https://github.com/nfroidure/ttf2woff2/blob/main/csrc/addon.cc#L27
[2] https://github.com/google/sanitizers/wiki/addresssanitizer

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions