Print this page
3849 implement __cxa_atexit/__cxa_finalize

Split Close
Expand all
Collapse all
          --- old/usr/src/lib/libc/port/gen/atexit.c
          +++ new/usr/src/lib/libc/port/gen/atexit.c
↓ open down ↓ 44 lines elided ↑ open up ↑
  45   45   * to malloc occuring before main will crash.  The loader calls atexit(3C)
  46   46   * before calling main, so we'd better avoid malloc() when it does.
  47   47   *
  48   48   * Another reason for using lmalloc()/lfree() is that the atexit()
  49   49   * list must transcend all link maps.  See the Linker and Libraries
  50   50   * Guide for information on alternate link maps.
  51   51   *
  52   52   * See "thr_uberdata.h" for the definitions of structures used here.
  53   53   */
  54   54  
  55      -static int in_range(_exithdlr_func_t, Lc_addr_range_t[], uint_t count);
       55 +static int in_range(void *, Lc_addr_range_t[], uint_t count);
  56   56  
  57   57  extern  caddr_t _getfp(void);
  58   58  
  59   59  /*
  60   60   * exitfns_lock is declared to be a recursive mutex so that we
  61   61   * can hold it while calling out to the registered functions.
  62   62   * If they call back to us, we are self-consistent and everything
  63   63   * works, even the case of calling exit() from functions called
  64   64   * by _exithandle() (recursive exit()).  All that is required is
  65   65   * that the registered functions actually return (no longjmp()s).
↓ open down ↓ 15 lines elided ↑ open up ↑
  81   81  {
  82   82          (void) mutex_lock(&__uberdata.atexit_root.exitfns_lock);
  83   83  }
  84   84  
  85   85  void
  86   86  atexit_unlocks()
  87   87  {
  88   88          (void) mutex_unlock(&__uberdata.atexit_root.exitfns_lock);
  89   89  }
  90   90  
       91 +
  91   92  /*
  92   93   * atexit() is called before the primordial thread is fully set up.
  93   94   * Be careful about dereferencing self->ul_uberdata->atexit_root.
  94   95   */
  95   96  int
  96      -atexit(void (*func)(void))
       97 +__cxa_atexit(void (*hdlr)(void *), void *arg, void *dso)
  97   98  {
  98   99          ulwp_t *self;
  99  100          atexit_root_t *arp;
 100  101          _exthdlr_t *p;
 101  102  
 102  103          if ((p = lmalloc(sizeof (_exthdlr_t))) == NULL)
 103  104                  return (-1);
 104  105  
 105  106          if ((self = __curthread()) == NULL)
 106  107                  arp = &__uberdata.atexit_root;
 107  108          else {
 108  109                  arp = &self->ul_uberdata->atexit_root;
 109  110                  (void) mutex_lock(&arp->exitfns_lock);
 110  111          }
 111      -        p->hdlr = func;
      112 +        p->hdlr = hdlr;
      113 +        p->arg = arg;
      114 +        p->dso = dso;
 112  115          p->next = arp->head;
 113  116          arp->head = p;
      117 +
 114  118          if (self != NULL)
 115  119                  (void) mutex_unlock(&arp->exitfns_lock);
 116  120          return (0);
 117  121  }
 118  122  
      123 +int
      124 +atexit(void (*func)(void))
      125 +{
      126 +        return (__cxa_atexit((_exithdlr_func_t)func, NULL, NULL));
      127 +}
      128 +
      129 +/*
      130 + * Note that we may be entered recursively, as we'll call __cxa_finalize(0) at
      131 + * exit, one of our handlers is ld.so.1`atexit_fini, and libraries may call
      132 + * __cxa_finalize(__dso_handle) from their _fini.
      133 + */
 119  134  void
 120      -_exithandle(void)
      135 +__cxa_finalize(void *dso)
 121  136  {
 122  137          atexit_root_t *arp = &curthread->ul_uberdata->atexit_root;
 123      -        _exthdlr_t *p;
      138 +        _exthdlr_t *p, *o;
 124  139          int cancel_state;
 125  140  
 126  141          /* disable cancellation while running atexit handlers */
 127  142          (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_state);
 128  143          (void) mutex_lock(&arp->exitfns_lock);
 129      -        arp->exit_frame_monitor = _getfp() + STACK_BIAS;
      144 +
      145 +        o = NULL;
 130  146          p = arp->head;
 131  147          while (p != NULL) {
 132      -                arp->head = p->next;
 133      -                p->hdlr();
 134      -                lfree(p, sizeof (_exthdlr_t));
 135      -                p = arp->head;
      148 +                if ((dso == NULL) || (p->dso == dso)) {
      149 +                        if (o != NULL)
      150 +                                o->next = p->next;
      151 +                        else
      152 +                                arp->head = p->next;
      153 +
      154 +                        p->hdlr(p->arg);
      155 +                        lfree(p, sizeof (_exthdlr_t));
      156 +                        o = NULL;
      157 +                        p = arp->head;
      158 +                } else {
      159 +                        o = p;
      160 +                        p = p->next;
      161 +                }
 136  162          }
      163 +
 137  164          (void) mutex_unlock(&arp->exitfns_lock);
 138  165          (void) pthread_setcancelstate(cancel_state, NULL);
 139  166  }
 140  167  
      168 +void
      169 +_exithandle(void)
      170 +{
      171 +        atexit_root_t *arp = &curthread->ul_uberdata->atexit_root;
      172 +
      173 +        arp->exit_frame_monitor = _getfp() + STACK_BIAS;
      174 +        __cxa_finalize(NULL);
      175 +}
      176 +
 141  177  /*
 142  178   * _get_exit_frame_monitor is called by the C++ runtimes.
 143  179   */
 144  180  void *
 145  181  _get_exit_frame_monitor(void)
 146  182  {
 147  183          atexit_root_t *arp = &curthread->ul_uberdata->atexit_root;
 148  184          return (&arp->exit_frame_monitor);
 149  185  }
 150  186  
↓ open down ↓ 11 lines elided ↑ open up ↑
 162  198          rwlock_t *rwlp;
 163  199          struct sigaction *sap;
 164  200          struct sigaction oact;
 165  201          void (*handler)();
 166  202  
 167  203          for (sig = 1; sig < NSIG; sig++) {
 168  204                  sap = (struct sigaction *)&udp->siguaction[sig].sig_uaction;
 169  205  again:
 170  206                  handler = sap->sa_handler;
 171  207                  if (handler != SIG_DFL && handler != SIG_IGN &&
 172      -                    in_range(handler, range, count)) {
      208 +                    in_range((void *)handler, range, count)) {
 173  209                          rwlp = &udp->siguaction[sig].sig_lock;
 174  210                          lrw_wrlock(rwlp);
 175  211                          if (handler != sap->sa_handler) {
 176  212                                  lrw_unlock(rwlp);
 177  213                                  goto again;
 178  214                          }
 179  215                          sap->sa_handler = SIG_DFL;
 180  216                          sap->sa_flags = SA_SIGINFO;
 181  217                          (void) sigemptyset(&sap->sa_mask);
 182  218                          if (__sigaction(sig, NULL, &oact) == 0 &&
↓ open down ↓ 23 lines elided ↑ open up ↑
 206  242          int start_again;
 207  243  
 208  244          (void) mutex_lock(&udp->atfork_lock);
 209  245          if ((atfork_q = udp->atforklist) != NULL) {
 210  246                  atfp = atfork_q;
 211  247                  do {
 212  248                          next = atfp->forw;
 213  249                          start_again = 0;
 214  250  
 215  251                          if (((func = atfp->prepare) != NULL &&
 216      -                            in_range(func, range, count)) ||
      252 +                            in_range((void *)func, range, count)) ||
 217  253                              ((func = atfp->parent) != NULL &&
 218      -                            in_range(func, range, count)) ||
      254 +                            in_range((void *)func, range, count)) ||
 219  255                              ((func = atfp->child) != NULL &&
 220      -                            in_range(func, range, count))) {
      256 +                            in_range((void *)func, range, count))) {
 221  257                                  if (self->ul_fork) {
 222  258                                          /*
 223  259                                           * dlclose() called from a fork handler.
 224  260                                           * Deleting the entry would wreak havoc.
 225  261                                           * Just null out the function pointers
 226  262                                           * and leave the entry in place.
 227  263                                           */
 228  264                                          atfp->prepare = NULL;
 229  265                                          atfp->parent = NULL;
 230  266                                          atfp->child = NULL;
↓ open down ↓ 30 lines elided ↑ open up ↑
 261  297  _preexec_tsd_unload(Lc_addr_range_t range[], uint_t count)
 262  298  {
 263  299          tsd_metadata_t *tsdm = &curthread->ul_uberdata->tsd_metadata;
 264  300          void (*func)(void *);
 265  301          int key;
 266  302  
 267  303          lmutex_lock(&tsdm->tsdm_lock);
 268  304          for (key = 1; key < tsdm->tsdm_nused; key++) {
 269  305                  if ((func = tsdm->tsdm_destro[key]) != NULL &&
 270  306                      func != TSD_UNALLOCATED &&
 271      -                    in_range((_exithdlr_func_t)func, range, count))
      307 +                    in_range((void *)func, range, count))
 272  308                          tsdm->tsdm_destro[key] = NULL;
 273  309          }
 274  310          lmutex_unlock(&tsdm->tsdm_lock);
 275  311  }
 276  312  
 277  313  /*
 278  314   * The following is a routine which the loader (ld.so.1) calls when it
 279  315   * processes dlclose calls on objects with atexit registrations.  It
 280  316   * executes the exit handlers that fall within the union of the ranges
 281  317   * specified by the elements of the array range in the REVERSE ORDER of
↓ open down ↓ 7 lines elided ↑ open up ↑
 289  325          _exthdlr_t *o;          /* previous node */
 290  326          _exthdlr_t *p;          /* this node */
 291  327          int cancel_state;
 292  328  
 293  329          /* disable cancellation while running atexit handlers */
 294  330          (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_state);
 295  331          (void) mutex_lock(&arp->exitfns_lock);
 296  332          o = NULL;
 297  333          p = arp->head;
 298  334          while (p != NULL) {
 299      -                if (in_range(p->hdlr, range, count)) {
      335 +                /*
      336 +                 * We call even CXA handlers of functions present in the
      337 +                 * library being unloaded.  The specification isn't
      338 +                 * particularly clear on this, and this seems the most sane.
      339 +                 * This is the behaviour of FreeBSD 9.1 (GNU libc leaves the
      340 +                 * handler on the exit list, and crashes at exit time).
      341 +                 *
      342 +                 * This won't cause handlers to be called twice, because
      343 +                 * anything called from a __cxa_finalize call from the
      344 +                 * language runtime will have been removed from the list.
      345 +                 */
      346 +                if (in_range((void *)p->hdlr, range, count)) {
 300  347                          /* We need to execute this one */
 301  348                          if (o != NULL)
 302  349                                  o->next = p->next;
 303  350                          else
 304  351                                  arp->head = p->next;
 305      -                        p->hdlr();
      352 +                        p->hdlr(p->arg);
 306  353                          lfree(p, sizeof (_exthdlr_t));
 307  354                          o = NULL;
 308  355                          p = arp->head;
 309  356                  } else {
 310  357                          o = p;
 311  358                          p = p->next;
 312  359                  }
 313  360          }
 314  361          (void) mutex_unlock(&arp->exitfns_lock);
 315  362          (void) pthread_setcancelstate(cancel_state, NULL);
 316  363  
 317  364          _preexec_tsd_unload(range, count);
 318  365          _preexec_atfork_unload(range, count);
 319  366          _preexec_sig_unload(range, count);
 320  367  
 321  368          return (0);
 322  369  }
 323  370  
 324  371  static int
 325      -in_range(_exithdlr_func_t addr, Lc_addr_range_t ranges[], uint_t count)
      372 +in_range(void *addr, Lc_addr_range_t ranges[], uint_t count)
 326  373  {
 327  374          uint_t idx;
 328  375  
 329  376          for (idx = 0; idx < count; idx++) {
 330      -                if ((void *)addr >= ranges[idx].lb &&
 331      -                    (void *)addr < ranges[idx].ub) {
      377 +                if (addr >= ranges[idx].lb &&
      378 +                    addr < ranges[idx].ub) {
 332  379                          return (1);
 333  380                  }
 334  381          }
 335  382  
 336  383          return (0);
 337  384  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX