Ticket #12005: 0002-Make-sure-images-containing-BTranslators-are-not-unl.2.patch

File 0002-Make-sure-images-containing-BTranslators-are-not-unl.2.patch, 12.8 KB (added by TwoFx, 9 years ago)

Replacement for the other patch 0002

  • headers/os/app/AppDefs.h

    From 984306d182574cc00f9607f96872eb9db4e88c72 Mon Sep 17 00:00:00 2001
    From: Markus Himmel <markus@himmel-villmar.de>
    Date: Sun, 8 Nov 2015 15:16:05 +0000
    Subject: [PATCH 2/2] Make sure images containing BTranslators are not unloaded
     early
    
    When a translator is uninstalled, BTranslatorPrivate::_RemoveTranslators is
    called. This method used to unload the image containing the translator after
    calling Release() on it resulting in several problems:
    
    - If the translator was still busy, e.g. translating something while being
      installed, it crashed since the image was unloaded even though its refcount
      was larger than 0.
    - Applications using code from one of the translators (e.g. its config view)
      would crash when the translator is uninstalled (this is bug #12005).
    
    This problem is now fixed. The roster keeps track of all translators whose
    image it manages (even if the translator was already removed from the roster).
    It also keeps a refcount to all images. When a translator's refcount drops to
    zero and it belonged to a roster at some point, it does not delete itself, but
    notifies the roster that it is ready to destruct, which then removes it from
    the roster if the translator is still in it, destroys the translator, decrements
    the refcount of the image and if the new refcount is zero, unloads the image.
    All of this is done in a message handler, since if the translator called
    TranslatorDeleted like before, the unloaded image would be referenced when
    the stack is walked up.
    
    Finally, the DataTranslations preflet is required to Acquire() the translator
    whose config view it is showing, because otherwise its refcount could be reduced
    to 0 and the image unloaded. BTranslatorRoster now enables users to acquire a
    translator by ID. By the time the translator has to be released, it might not
    be part of the roster anymore though. Since BTranslatorRoster tries not to give
    out raw pointers to the translators it manages, users who acquire a translator
    through a roster now are given a BTranslatorReleaseDelegate, which allows for
    releasing the BTranslator exactly once and then self-destructs.
    ---
     headers/os/app/AppDefs.h                           |  1 +
     headers/os/translation/TranslatorRoster.h          | 13 ++++
     src/kits/translation/Translator.cpp                | 20 ++++--
     src/kits/translation/TranslatorRoster.cpp          | 79 +++++++++++++++++-----
     src/kits/translation/TranslatorRosterPrivate.h     |  8 ++-
     .../datatranslations/DataTranslationsWindow.cpp    | 16 ++++-
     .../datatranslations/DataTranslationsWindow.h      |  2 +
     7 files changed, 115 insertions(+), 24 deletions(-)
    
    diff --git a/headers/os/app/AppDefs.h b/headers/os/app/AppDefs.h
    index 77383ef..0a70d8b 100644
    a b enum {  
    5959    B_VALUE_CHANGED             = '_VCH',
    6060    B_TRANSLATOR_ADDED          = '_ART',
    6161    B_TRANSLATOR_REMOVED        = '_RRT',
     62    B_DELETE_TRANSLATOR         = '_DRT',
    6263    B_VIEW_MOVED                = '_VMV',
    6364    B_VIEW_RESIZED              = '_VRS',
    6465    B_WINDOW_MOVED              = '_WMV',
  • headers/os/translation/TranslatorRoster.h

    diff --git a/headers/os/translation/TranslatorRoster.h b/headers/os/translation/TranslatorRoster.h
    index 4d95853..b01d9c2 100644
    a b class BView;  
    2323struct entry_ref;
    2424
    2525
     26class BTranslatorReleaseDelegate {
     27public:
     28                                BTranslatorReleaseDelegate(BTranslator* translator);
     29
     30            void                Release();
     31
     32private:
     33            BTranslator*        fUnderlying;
     34};
     35
     36
    2637class BTranslatorRoster : public BArchivable {
    2738public:
    2839                                BTranslatorRoster();
    public:  
    8697                                    translator_id translatorID,
    8798                                    BMessage* ioExtension);
    8899
     100            BTranslatorReleaseDelegate* AcquireTranslator(int32 translatorID);
     101
    89102            status_t            GetRefFor(translator_id translatorID,
    90103                                    entry_ref* ref);
    91104            bool                IsTranslator(entry_ref* ref);
  • src/kits/translation/Translator.cpp

    diff --git a/src/kits/translation/Translator.cpp b/src/kits/translation/Translator.cpp
    index 5699901..6afb80c 100644
    a b BTranslator::BTranslator()  
    2424
    2525BTranslator::~BTranslator()
    2626{
    27     if (fOwningRoster != NULL)
    28         fOwningRoster->TranslatorDeleted(fID);
    2927}
    3028
    3129
    BTranslator *BTranslator::Acquire()  
    5250BTranslator *BTranslator::Release()
    5351{
    5452    int32 oldValue = atomic_add(&fRefCount, -1);
    55     if (oldValue > 0)
     53    if (oldValue > 1)
    5654        return this;
    5755
    58     delete this;
     56    if (fOwningRoster == NULL) {
     57        delete this;
     58        return NULL;
     59    }
     60
     61    // If we have ever been part of a roster, notify the roster to delete us
     62    // and unload our image in a thread-safe way
     63    BMessage deleteRequest(B_DELETE_TRANSLATOR);
     64
     65    deleteRequest.AddPointer("ptr", this);
     66    deleteRequest.AddInt32("id", fID);
     67
     68    BMessenger sender(fOwningRoster);
     69    sender.SendMessage(&deleteRequest);
     70
    5971    return NULL;
    6072}
    6173
  • src/kits/translation/TranslatorRoster.cpp

    diff --git a/src/kits/translation/TranslatorRoster.cpp b/src/kits/translation/TranslatorRoster.cpp
    index a0b54af..4e3f7c2 100644
    a b BTranslatorRoster::Private::~Private()  
    193193    while (iterator != fTranslators.end()) {
    194194        BTranslator* translator = iterator->second.translator;
    195195
    196         translator->fOwningRoster = NULL;
    197             // we don't want to be notified about this anymore
    198 
    199196        images.insert(iterator->second.image);
    200197        translator->Release();
    201198
    BTranslatorRoster::Private::MessageReceived(BMessage* message)  
    318315            break;
    319316        }
    320317
     318        case B_DELETE_TRANSLATOR:
     319        {
     320            // A translator's refcount has been reduced to zero and it wants
     321            // us to delete it.
     322            int32 id;
     323            void* self;
     324            if (message->FindInt32("id", &id) == B_OK
     325                && message->FindPointer("ptr", &self) == B_OK) {
     326                _TranslatorDeleted(id, (BTranslator*)self);
     327            }
     328            break;
     329        }
     330
    321331        default:
    322332            BHandler::MessageReceived(message);
    323333            break;
    BTranslatorRoster::Private::CreateTranslators(const entry_ref& ref,  
    592602            if (AddTranslator(translator, image, &ref, nodeRef.node) == B_OK) {
    593603                if (update)
    594604                    update->AddInt32("translator_id", translator->fID);
     605                fImageOrigins.insert(std::make_pair(translator, image));
    595606                count++;
    596607                created++;
    597608            } else {
    BTranslatorRoster::Private::CreateTranslators(const entry_ref& ref,  
    600611            }
    601612        }
    602613
    603         if (created == 0)
     614        if (created == 0) {
    604615            unload_add_on(image);
     616        } else {
     617            // Initial refcount for the image that was just loaded
     618            fKnownImages.insert(std::make_pair(image, created));
     619        }
    605620
    606621        quarantine.Remove();
    607622        return B_OK;
    BTranslatorRoster::Private::GetRefFor(translator_id id, entry_ref& ref)  
    850865
    851866
    852867void
    853 BTranslatorRoster::Private::TranslatorDeleted(translator_id id)
     868BTranslatorRoster::Private::_TranslatorDeleted(translator_id id, BTranslator* self)
    854869{
    855870    BAutolock locker(this);
    856871
    857872    TranslatorMap::iterator iterator = fTranslators.find(id);
    858     if (iterator == fTranslators.end())
    859         return;
     873    if (iterator != fTranslators.end())
     874        fTranslators.erase(iterator);
    860875
    861     fTranslators.erase(iterator);
    862 }
     876    image_id image = fImageOrigins[self];
     877
     878    delete self;
    863879
     880    int32 former = atomic_add(&fKnownImages[image], -1);
     881    if (former == 1)
     882    {
     883        unload_add_on(image);
     884        fImageOrigins.erase(self);
     885        fKnownImages.erase(image);
     886    }
     887}
    864888
    865889/*static*/ int
    866890BTranslatorRoster::Private::_CompareSupport(const void* _a, const void* _b)
    BTranslatorRoster::Private::_RemoveTranslators(const node_ref* nodeRef,  
    10731097        if ((ref != NULL && item.ref == *ref)
    10741098            || (nodeRef != NULL && item.ref.device == nodeRef->device
    10751099                && item.node == nodeRef->node)) {
    1076             item.translator->fOwningRoster = NULL;
    1077                 // if the translator is busy, we don't want to be notified
    1078                 // about the removal later on
    10791100            item.translator->Release();
    10801101            image = item.image;
    10811102            update.AddInt32("translator_id", iterator->first);
    BTranslatorRoster::Private::_RemoveTranslators(const node_ref* nodeRef,  
    10861107        iterator = next;
    10871108    }
    10881109
    1089     // Unload image from the removed translator
    1090 
    1091     if (image >= B_OK)
    1092         unload_add_on(image);
    1093 
    10941110    _NotifyListeners(update);
    10951111}
    10961112
    BTranslatorRoster::Private::_NotifyListeners(BMessage& update) const  
    11501166
    11511167//  #pragma mark -
    11521168
     1169BTranslatorReleaseDelegate::BTranslatorReleaseDelegate(BTranslator* translator)
     1170    :
     1171    fUnderlying(translator)
     1172{
     1173}
     1174
     1175
     1176void
     1177BTranslatorReleaseDelegate::Release()
     1178{
     1179    fUnderlying->Release();
     1180    // ReleaseDelegate is only allowed to release a translator once.
     1181    delete this;
     1182}
     1183
    11531184
    11541185BTranslatorRoster::BTranslatorRoster()
    11551186{
    BTranslatorRoster::MakeConfigurationView(translator_id id,  
    16651696}
    16661697
    16671698
     1699BTranslatorReleaseDelegate*
     1700BTranslatorRoster::AcquireTranslator(int32 id)
     1701{
     1702    BAutolock locker(fPrivate);
     1703
     1704    BTranslator* translator = fPrivate->FindTranslator(id);
     1705    if (translator == NULL)
     1706        return NULL;
     1707
     1708    translator->Acquire();
     1709    return new BTranslatorReleaseDelegate(translator);
     1710}
     1711
     1712
    16681713/*!
    16691714    Gets the configuration setttings for the translator
    16701715    specified by \a id and puts them into \a ioExtension.
  • src/kits/translation/TranslatorRosterPrivate.h

    diff --git a/src/kits/translation/TranslatorRosterPrivate.h b/src/kits/translation/TranslatorRosterPrivate.h
    index dac2c01..ceb9d3d 100644
    a b typedef std::map<translator_id, translator_item> TranslatorMap;  
    3333typedef std::vector<BMessenger> MessengerList;
    3434typedef std::vector<node_ref> NodeRefList;
    3535typedef std::set<entry_ref> EntryRefSet;
     36typedef std::map<image_id, int32> ImageMap;
     37typedef std::map<BTranslator*, image_id> TranslatorImageMap;
    3638
    3739
    3840class BTranslatorRoster::Private : public BHandler, public BLocker {
    public:  
    7880            status_t            StartWatching(BMessenger target);
    7981            status_t            StopWatching(BMessenger target);
    8082
    81             void                TranslatorDeleted(translator_id id);
    82 
    8383private:
    8484    static  int                 _CompareSupport(const void* _a, const void* _b);
    8585
    private:  
    107107                                    const char* name);
    108108            void                _EntryAdded(const entry_ref& ref);
    109109            void                _NotifyListeners(BMessage& update) const;
     110            void                _TranslatorDeleted(translator_id id,
     111                                    BTranslator *self);
    110112
    111113            NodeRefList         fDirectories;
    112114            TranslatorMap       fTranslators;
    113115            MessengerList       fMessengers;
    114116            EntryRefSet         fRescanEntries;
     117            ImageMap            fKnownImages;
     118            TranslatorImageMap  fImageOrigins;
    115119            const char*         fABISubDirectory;
    116120            int32               fNextID;
    117121            bool                fLazyScanning;
  • src/preferences/datatranslations/DataTranslationsWindow.cpp

    diff --git a/src/preferences/datatranslations/DataTranslationsWindow.cpp b/src/preferences/datatranslations/DataTranslationsWindow.cpp
    index 24b83e5..c1ce982 100644
    a b DataTranslationsWindow::DataTranslationsWindow()  
    5353    :
    5454    BWindow(BRect(0, 0, 550, 350), B_TRANSLATE_SYSTEM_NAME("DataTranslations"),
    5555        B_TITLED_WINDOW, B_ASYNCHRONOUS_CONTROLS | B_NOT_ZOOMABLE
    56         | B_NOT_RESIZABLE | B_AUTO_UPDATE_SIZE_LIMITS)
     56        | B_NOT_RESIZABLE | B_AUTO_UPDATE_SIZE_LIMITS),
     57    fRelease(NULL)
    5758{
    5859    MoveTo(DataTranslationsSettings::Instance()->WindowCorner());
    5960
    DataTranslationsWindow::_ShowConfigView(int32 id)  
    151152        fRightBox->RemoveChild(fConfigView);
    152153        delete fConfigView;
    153154        fConfigView = NULL;
     155        if (fRelease != NULL) {
     156            fRelease->Release();
     157            fRelease = NULL;
     158        }
    154159    }
    155160
    156161    BMessage emptyMsg;
    DataTranslationsWindow::_ShowConfigView(int32 id)  
    165170        // force config views to all have the same color
    166171    fRightBox->AddChild(fConfigView);
    167172
     173    // Make sure the translator's image doesn't get unloaded while we are still
     174    // showing a config view whose code is in the image
     175    fRelease = roster->AcquireTranslator(id);
     176
    168177    return B_OK;
    169178}
    170179
    DataTranslationsWindow::_ShowInfoView()  
    176185        fRightBox->RemoveChild(fConfigView);
    177186        delete fConfigView;
    178187        fConfigView = NULL;
     188        if (fRelease != NULL) {
     189            fRelease->Release();
     190            fRelease = NULL;
     191        }
     192
    179193    }
    180194
    181195    BTextView* view = new BTextView("info text");
  • src/preferences/datatranslations/DataTranslationsWindow.h

    diff --git a/src/preferences/datatranslations/DataTranslationsWindow.h b/src/preferences/datatranslations/DataTranslationsWindow.h
    index 68e4207..1e1f634 100644
    a b  
    2020
    2121#include "TranslatorListView.h"
    2222
     23class BTranslatorReleaseDelegate;
    2324
    2425class DataTranslationsWindow : public BWindow {
    2526public:
    private:  
    3940            void            _SetupViews();
    4041
    4142            TranslatorListView* fTranslatorListView;
     43            BTranslatorReleaseDelegate*     fRelease;
    4244
    4345            BBox*           fRightBox;
    4446            BView*          fConfigView;