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

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

Patch (part 2)

  • headers/os/app/AppDefs.h

    From b1b3bd819157fa0a438b17966ecfb1c09dba7d79 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          | 12 +++-
     src/kits/translation/Translator.cpp                | 21 ++++--
     src/kits/translation/TranslatorRoster.cpp          | 75 +++++++++++++++++-----
     src/kits/translation/TranslatorRosterPrivate.h     |  9 ++-
     .../datatranslations/DataTranslationsWindow.cpp    | 16 ++++-
     .../datatranslations/DataTranslationsWindow.h      |  3 +
     7 files changed, 111 insertions(+), 26 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..06f31ff 100644
    a b  
    99#include <Archivable.h>
    1010#include <TranslationDefs.h>
    1111
    12 
    1312struct translation_format;
    1413
    1514class BBitmap;
    class BTranslator;  
    2221class BView;
    2322struct entry_ref;
    2423
     24class BTranslatorReleaseDelegate {
     25public:
     26                                BTranslatorReleaseDelegate(BTranslator* it);
     27
     28            void                Release();
     29
     30private:
     31            BTranslator*        fUnderlying;
     32};
    2533
    2634class BTranslatorRoster : public BArchivable {
    2735public:
    public:  
    8694                                    translator_id translatorID,
    8795                                    BMessage* ioExtension);
    8896
     97            BTranslatorReleaseDelegate* AcquireTranslator(int32 translatorID);
     98
    8999            status_t            GetRefFor(translator_id translatorID,
    90100                                    entry_ref* ref);
    91101            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..33e91ab 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 del(B_DELETE_TRANSLATOR);
     64
     65    del.AddPointer("ptr", this);
     66    del.AddInt32("id", fID);
     67
     68    BMessenger sender(fOwningRoster);
     69    sender.SendMessage(&del);
     70
    5971    return NULL;
    6072}
    6173
    62 
    6374int32
    6475BTranslator::ReferenceCount()
    6576{
  • src/kits/translation/TranslatorRoster.cpp

    diff --git a/src/kits/translation/TranslatorRoster.cpp b/src/kits/translation/TranslatorRoster.cpp
    index a0b54af..12a5724 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];
    863877
     878    delete self;
     879
     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* it)
     1170    :
     1171    fUnderlying(it)
     1172{
     1173}
     1174
     1175void BTranslatorReleaseDelegate::Release()
     1176{
     1177    fUnderlying->Release();
     1178    // ReleaseDelegate is only allowed to release a translator once.
     1179    delete this;
     1180}
     1181
    11531182
    11541183BTranslatorRoster::BTranslatorRoster()
    11551184{
    BTranslatorRoster::MakeConfigurationView(translator_id id,  
    16641693    return translator->MakeConfigurationView(ioExtension, _view, _extent);
    16651694}
    16661695
     1696BTranslatorReleaseDelegate*
     1697BTranslatorRoster::AcquireTranslator(int32 id)
     1698{
     1699    BAutolock locker(fPrivate);
     1700
     1701    BTranslator* translator = fPrivate->FindTranslator(id);
     1702    if (translator == NULL)
     1703        return NULL;
     1704
     1705    translator->Acquire();
     1706    return new BTranslatorReleaseDelegate(translator);
     1707}
    16671708
    16681709/*!
    16691710    Gets the configuration setttings for the translator
  • src/kits/translation/TranslatorRosterPrivate.h

    diff --git a/src/kits/translation/TranslatorRosterPrivate.h b/src/kits/translation/TranslatorRosterPrivate.h
    index dac2c01..956f980 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);
     112
    110113
    111114            NodeRefList         fDirectories;
    112115            TranslatorMap       fTranslators;
    113116            MessengerList       fMessengers;
    114117            EntryRefSet         fRescanEntries;
     118            ImageMap            fKnownImages;
     119            TranslatorImageMap  fImageOrigins;
    115120            const char*         fABISubDirectory;
    116121            int32               fNextID;
    117122            bool                fLazyScanning;
  • src/preferences/datatranslations/DataTranslationsWindow.cpp

    diff --git a/src/preferences/datatranslations/DataTranslationsWindow.cpp b/src/preferences/datatranslations/DataTranslationsWindow.cpp
    index 2d71c40..4543c81 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..ce988ec 100644
    a b  
    2020
    2121#include "TranslatorListView.h"
    2222
     23class BTranslatorReleaseDelegate;
    2324
    2425class DataTranslationsWindow : public BWindow {
    2526public:
    private:  
    4041
    4142            TranslatorListView* fTranslatorListView;
    4243
     44            BTranslatorReleaseDelegate*     fRelease;
     45
    4346            BBox*           fRightBox;
    4447            BView*          fConfigView;
    4548            IconView*       fIconView;