pybind / pybind11

Seamless operability between C++11 and Python
https://pybind11.readthedocs.io/
Other
15.7k stars 2.1k forks source link

[BUG]: ASAN reports that allocated ptr is not deallocated properly. #3864

Open b0bleet opened 2 years ago

b0bleet commented 2 years ago

Required prerequisites

Problem description

Hi, ASAN reports that https://github.com/pybind/pybind11/blob/6493f496e30c80f004772c906370c8f4db94b6ec/include/pybind11/detail/internals.h#L498-L508 allocated ptr variable in internals.h:504 is not deallocated properly when calling finalize_interpreter few times. ASAN report:

==497630==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 8 byte(s) in 1 object(s) allocated from:
    #0 0x7f80838e8587 in operator new(unsigned long) ../../../../src/libsanitizer/asan/asan_new_delete.cc:104
    #1 0x557df8f07925 in pybind11::detail::local_internals::local_internals() /home/vmcs/projects/scanner/vendor/pybind11/include/pybind11/detail/../detail/internals.h:504
    #2 0x557df8f07925 in pybind11::detail::get_local_internals() /home/vmcs/projects/scanner/vendor/pybind11/include/pybind11/detail/../detail/internals.h:514
    #3 0x557df8f07925 in pybind11::finalize_interpreter() /home/vmcs/projects/scanner/vendor/pybind11/include/pybind11/embed.h:203

Reproducible example code

int test_lib() {
  py::initialize_interpreter();
  try {
    py::object mainScope = py::module::import("__main__").attr("__dict__");
    py::exec( "print('hello')", mainScope);
  } catch(pybind11::error_already_set const& ex) {
    std::cerr << " [PYBIND11 ERROR] " << ex.what() << std::endl;
    return EXIT_FAILURE;
  }
  py::finalize_interpreter();
  return 0;
}
int main() {
  for(int i = 0; i < 10; i ++) {
    test_lib();
  }
}
hardsetting commented 2 years ago

Following, as I'm having a similar issue. Using pybind11 v2.5.0, just by

I get a

free() invalid pointer

after deallocation, and debugging that seems to be triggered when deleting a key string in the internals::shared_data unordered_map (value of the string seems to be "_life_support")

I thought it was something within the particular module I was importing, but this makes me believe it's something within pybind11

EDIT: I get the free(): invalid pointer error importing either scipy.signal or sklearn. Most other modules are fine

# These are fine
import numpy as np
import math
import copy
import logging
import yaml
from pickle import dump, load
from os.path import join, isfile
from collections import deque, Counter
from random import seed

# Any of these triggers the segfault
# from scipy.signal import butter, lfilter
# from scipy.stats import iqr, linregress
# from scipy.signal import find_peaks
# from sklearn.tree import DecisionTreeClassifier
# from sklearn.ensemble import RandomForestClassifier
# from sklearn import preprocessing, metrics