HaikuDepot: Make BitmapView use SharedBitmaps directly.

Instead of extracting a BBitmap out of the SharedBitmap and giving that
to BitmapView, set SharedBitmaps directly. When using BBitmaps we
circumvent the reference counting of the SharedBitmaps and it would be
possible for the SharedBitmap and its BBitmaps to get deleted while
one of them was still used in a BitmapView.

Fixes use-after-free when icons are updated that are already used in
BitmapViews.
This commit is contained in:
Michael Lotz 2015-04-08 10:16:54 +02:00
parent 3525a370d4
commit 2a36368bda
6 changed files with 62 additions and 38 deletions

View File

@ -151,16 +151,15 @@ public:
fPackageListener->SetPackage(package); fPackageListener->SetPackage(package);
if (package->Icon().Get() != NULL) { if (package->Icon().Get() != NULL) {
fIconView->SetBitmap( fIconView->SetBitmap(package->Icon(), SharedBitmap::SIZE_64);
package->Icon()->Bitmap(SharedBitmap::SIZE_64));
} else } else
fIconView->SetBitmap(NULL); fIconView->UnsetBitmap();
if (package->State() == ACTIVATED) { if (package->State() == ACTIVATED) {
fInstalledIconView->SetBitmap( fInstalledIconView->SetBitmap(sInstalledIcon,
sInstalledIcon->Bitmap(SharedBitmap::SIZE_16)); SharedBitmap::SIZE_16);
} else } else
fInstalledIconView->SetBitmap(NULL); fInstalledIconView->UnsetBitmap();
fTitleView->SetText(package->Title()); fTitleView->SetText(package->Title());
@ -199,8 +198,8 @@ public:
{ {
fPackageListener->SetPackage(PackageInfoRef(NULL)); fPackageListener->SetPackage(PackageInfoRef(NULL));
fIconView->SetBitmap(NULL); fIconView->UnsetBitmap();
fInstalledIconView->SetBitmap(NULL); fInstalledIconView->UnsetBitmap();
fTitleView->SetText(""); fTitleView->SetText("");
fPublisherView->SetText(""); fPublisherView->SetText("");
fSummaryView->SetText(""); fSummaryView->SetText("");

View File

@ -391,9 +391,9 @@ public:
void SetPackage(const PackageInfo& package) void SetPackage(const PackageInfo& package)
{ {
if (package.Icon().Get() != NULL) if (package.Icon().Get() != NULL)
fIconView->SetBitmap(package.Icon()->Bitmap(SharedBitmap::SIZE_32)); fIconView->SetBitmap(package.Icon(), SharedBitmap::SIZE_32);
else else
fIconView->SetBitmap(NULL); fIconView->UnsetBitmap();
fTitleView->SetText(package.Title()); fTitleView->SetText(package.Title());
@ -431,7 +431,7 @@ public:
void Clear() void Clear()
{ {
fIconView->SetBitmap(NULL); fIconView->UnsetBitmap();
fTitleView->SetText(""); fTitleView->SetText("");
fPublisherView->SetText(""); fPublisherView->SetText("");
fVersionInfo->SetText(""); fVersionInfo->SetText("");
@ -797,31 +797,36 @@ public:
fDescriptionView->SetText(package.ShortDescription(), fDescriptionView->SetText(package.ShortDescription(),
package.FullDescription()); package.FullDescription());
fEmailIconView->SetBitmap(fEmailIcon.Bitmap(SharedBitmap::SIZE_16)); fEmailIconView->SetBitmap(&fEmailIcon, SharedBitmap::SIZE_16);
_SetContactInfo(fEmailLinkView, package.Publisher().Email()); _SetContactInfo(fEmailLinkView, package.Publisher().Email());
fWebsiteIconView->SetBitmap(fWebsiteIcon.Bitmap(SharedBitmap::SIZE_16)); fWebsiteIconView->SetBitmap(&fWebsiteIcon, SharedBitmap::SIZE_16);
_SetContactInfo(fWebsiteLinkView, package.Publisher().Website()); _SetContactInfo(fWebsiteLinkView, package.Publisher().Website());
const BBitmap* screenshot = NULL; bool hasScreenshot = false;
const BitmapList& screenShots = package.Screenshots(); const BitmapList& screenShots = package.Screenshots();
if (screenShots.CountItems() > 0) { if (screenShots.CountItems() > 0) {
const BitmapRef& bitmapRef = screenShots.ItemAtFast(0); const BitmapRef& bitmapRef = screenShots.ItemAtFast(0);
if (bitmapRef.Get() != NULL) if (bitmapRef.Get() != NULL) {
screenshot = bitmapRef->Bitmap(SharedBitmap::SIZE_ANY); hasScreenshot = true;
fScreenshotView->SetBitmap(bitmapRef);
}
} }
fScreenshotView->SetBitmap(screenshot);
fScreenshotView->SetEnabled(screenshot != NULL); if (!hasScreenshot)
fScreenshotView->UnsetBitmap();
fScreenshotView->SetEnabled(hasScreenshot);
} }
void Clear() void Clear()
{ {
fDescriptionView->SetText(""); fDescriptionView->SetText("");
fEmailIconView->SetBitmap(NULL); fEmailIconView->UnsetBitmap();
fEmailLinkView->SetText(""); fEmailLinkView->SetText("");
fWebsiteIconView->SetBitmap(NULL); fWebsiteIconView->UnsetBitmap();
fWebsiteLinkView->SetText(""); fWebsiteLinkView->SetText("");
fScreenshotView->SetBitmap(NULL); fScreenshotView->UnsetBitmap();
fScreenshotView->SetEnabled(false); fScreenshotView->SetEnabled(false);
} }
@ -867,8 +872,8 @@ public:
fAvatarView = new BitmapView("avatar view"); fAvatarView = new BitmapView("avatar view");
if (rating.User().Avatar().Get() != NULL) { if (rating.User().Avatar().Get() != NULL) {
fAvatarView->SetBitmap( fAvatarView->SetBitmap(rating.User().Avatar(),
rating.User().Avatar()->Bitmap(SharedBitmap::SIZE_16)); SharedBitmap::SIZE_16);
} }
fAvatarView->SetExplicitMinSize(BSize(16.0f, 16.0f)); fAvatarView->SetExplicitMinSize(BSize(16.0f, 16.0f));
@ -908,10 +913,8 @@ public:
// fVoteDownIconView = new BitmapButton("vote down icon", voteDownMessage); // fVoteDownIconView = new BitmapButton("vote down icon", voteDownMessage);
// fDownVoteCountView = new BStringView("up vote count", ""); // fDownVoteCountView = new BStringView("up vote count", "");
// //
// fVoteUpIconView->SetBitmap( // fVoteUpIconView->SetBitmap(voteUpIcon, SharedBitmap::SIZE_16);
// voteUpIcon->Bitmap(SharedBitmap::SIZE_16)); // fVoteDownIconView->SetBitmap(voteDownIcon, SharedBitmap::SIZE_16);
// fVoteDownIconView->SetBitmap(
// voteDownIcon->Bitmap(SharedBitmap::SIZE_16));
// //
// fUpVoteCountView->SetFont(&versionFont); // fUpVoteCountView->SetFont(&versionFont);
// fUpVoteCountView->SetHighColor(kLightBlack); // fUpVoteCountView->SetHighColor(kLightBlack);

View File

@ -175,8 +175,8 @@ ScreenshotWindow::_DownloadThread()
return; return;
} }
fScreenshotView->SetBitmap(NULL); fScreenshotView->UnsetBitmap();
ScreenshotInfoList screenshotInfos; ScreenshotInfoList screenshotInfos;
if (fPackage.Get() != NULL) if (fPackage.Get() != NULL)
screenshotInfos = fPackage->ScreenshotInfos(); screenshotInfos = fPackage->ScreenshotInfos();
@ -202,7 +202,7 @@ ScreenshotWindow::_DownloadThread()
if (status == B_OK && Lock()) { if (status == B_OK && Lock()) {
printf("got screenshot"); printf("got screenshot");
fScreenshot = BitmapRef(new(std::nothrow)SharedBitmap(buffer), true); fScreenshot = BitmapRef(new(std::nothrow)SharedBitmap(buffer), true);
fScreenshotView->SetBitmap(fScreenshot->Bitmap(SharedBitmap::SIZE_ANY)); fScreenshotView->SetBitmap(fScreenshot);
_ResizeToFitAndCenter(); _ResizeToFitAndCenter();
Unlock(); Unlock();
} else { } else {

View File

@ -235,10 +235,9 @@ UserLoginWindow::MessageReceived(BMessage* message)
case MSG_CAPTCHA_OBTAINED: case MSG_CAPTCHA_OBTAINED:
if (fCaptchaImage.Get() != NULL) { if (fCaptchaImage.Get() != NULL) {
fCaptchaView->SetBitmap( fCaptchaView->SetBitmap(fCaptchaImage);
fCaptchaImage->Bitmap(SharedBitmap::SIZE_ANY));
} else { } else {
fCaptchaView->SetBitmap(NULL); fCaptchaView->UnsetBitmap();
} }
fCaptchaResultField->SetText(""); fCaptchaResultField->SetText("");
break; break;
@ -442,7 +441,7 @@ UserLoginWindow::_RequestCaptcha()
{ {
if (Lock()) { if (Lock()) {
fCaptchaToken = ""; fCaptchaToken = "";
fCaptchaView->SetBitmap(NULL); fCaptchaView->UnsetBitmap();
fCaptchaImage.Unset(); fCaptchaImage.Unset();
Unlock(); Unlock();
} }

View File

@ -131,14 +131,16 @@ BitmapView::MaxSize()
void void
BitmapView::SetBitmap(const BBitmap* bitmap) BitmapView::SetBitmap(SharedBitmap* bitmap, SharedBitmap::Size bitmapSize)
{ {
if (bitmap == fBitmap) if (bitmap == fReference && bitmapSize == fBitmapSize)
return; return;
BSize size = MinSize(); BSize size = MinSize();
fBitmap = bitmap; fReference.SetTo(bitmap);
fBitmapSize = bitmapSize;
fBitmap = bitmap->Bitmap(bitmapSize);
BSize newSize = MinSize(); BSize newSize = MinSize();
if (size != newSize) if (size != newSize)
@ -148,6 +150,20 @@ BitmapView::SetBitmap(const BBitmap* bitmap)
} }
void
BitmapView::UnsetBitmap()
{
if (fReference.Get() == NULL)
return;
fBitmap = NULL;
fReference.Unset();
InvalidateLayout();
Invalidate();
}
void void
BitmapView::SetScaleBitmap(bool scaleBitmap) BitmapView::SetScaleBitmap(bool scaleBitmap)
{ {

View File

@ -6,6 +6,8 @@
#define BITMAP_VIEW_H #define BITMAP_VIEW_H
#include "SharedBitmap.h"
#include <View.h> #include <View.h>
@ -22,7 +24,10 @@ public:
virtual BSize PreferredSize(); virtual BSize PreferredSize();
virtual BSize MaxSize(); virtual BSize MaxSize();
void SetBitmap(const BBitmap* bitmap); void SetBitmap(SharedBitmap* bitmap,
SharedBitmap::Size bitmapSize
= SharedBitmap::SIZE_ANY);
void UnsetBitmap();
void SetScaleBitmap(bool scaleBitmap); void SetScaleBitmap(bool scaleBitmap);
protected: protected:
@ -30,6 +35,8 @@ protected:
BRect updateRect); BRect updateRect);
private: private:
BitmapRef fReference;
SharedBitmap::Size fBitmapSize;
const BBitmap* fBitmap; const BBitmap* fBitmap;
bool fScaleBitmap; bool fScaleBitmap;
}; };