Closed
Bug 297277
Opened 19 years ago
Closed 19 years ago
potential OOM crash/mlk [@ nsPrintOptions::_CreatePrintSettings]
Categories
(Core :: Printing: Output, defect)
Tracking
()
RESOLVED
FIXED
People
(Reporter: timeless, Assigned: bastiaan)
References
()
Details
(Keywords: crash, memory-leak)
Crash Data
Attachments
(2 files, 17 obsolete files)
77.88 KB,
patch
|
dmosedale
:
superreview+
benjamin
:
approval1.8b4+
|
Details | Diff | Splinter Review |
72.15 KB,
patch
|
Details | Diff | Splinter Review |
this is an audit of sorts, it's based on a dreftool audit http://bonsai.mozilla.org/cvsblame.cgi?file=mozilla/gfx/src/nsPrintOptionsImpl.cpp&rev=1.67&mark=265#260 Deref-error: "sDefaultFont" http://bonsai.mozilla.org/cvsblame.cgi?file=mozilla/gfx/src/nsPrintOptionsImpl.cpp&rev=1.67&mark=887#882 Deref-error: "printSettings" and this is really a followup to bug 235643 ... bonus points for replacing SetLength(0) with Truncate() partial credit for fixing indentation to not have 3 space (code seems to be a mix of 1space, 2space, 3space, 4space, plus combinations)
Assignee | ||
Comment 1•19 years ago
|
||
> sDefaultFont = new nsFont(aFont); > aFont = *sDefaultFont; I don't see how these are dereferencing errors. Could you elaborate?
nothing makes sure the new doesn't fail. new is an alloc and can fail, presume we don't throw (because if we throw, the world ends, we try to ask vc6 and gcc not to throw [we incorrectly encourage vc7 to throw, but that's very much our fault and a regression]).
Assignee | ||
Comment 3•19 years ago
|
||
This patch fixes the dereferencing errors, and is a general cleanup of nsPrintOptionsImpl.*. It does in particular: * use the new string classes; * check for pointers/null correctly; * fix whitespacing and indentation; * more appropriate code patterns, return from errors immediately; * use macros for repetitive code; * null out _retvals; * ensure that parameter names (at least vaguely) reflect their purpose; * replaces SetLength(0) with Truncate().
Assignee: printing → baafie
Status: NEW → ASSIGNED
Assignee | ||
Comment 4•19 years ago
|
||
Assignee | ||
Comment 5•19 years ago
|
||
Comment on attachment 186174 [details] [diff] [review] cleanup patch (diff -u) I did a call for volunteers for reviewing this patch (since printing doesn't seem covered by any module owners/peers in particular), but there were none. So, I'm setting asking the same reviewers as I did for the last printing patch. I Hope that's okay.
Attachment #186174 -
Flags: superreview?(bzbarsky)
Attachment #186174 -
Flags: review?(timeless)
Comment on attachment 186174 [details] [diff] [review] cleanup patch (diff -u) i gave feedback to baafie on irc.
Attachment #186174 -
Flags: superreview?(bzbarsky)
Attachment #186174 -
Flags: review?(timeless)
Attachment #186174 -
Flags: review-
Comment 7•19 years ago
|
||
Comment on attachment 186174 [details] [diff] [review] cleanup patch (diff -u) + NS_ERROR("Operator new() returned nsnull; out of memory?"); (maybe timeless already mentioned this, but) you can't use NS_ERROR for OOM. it's an error you need to handle, you can't assert allocs succeed.
Assignee | ||
Comment 8•19 years ago
|
||
Summary of timeless' comments: <timeless> if [you have something in the constructor that] you need to init something that can fail, it really should be moved to an nsresult Init(){} method <timeless> NS_ENSURE_ARG_POINTER(sDefaultFont); -> NS_ENSURE_STATE(sDefaultFont); <timeless> NS_ENSURE_ARG_POINTER(ioParamBlock); -> NS_ENSURE_TRUE(.., OOM) <timeless> [whitespace alignment] <timeless> + NS_ADDREF(*aPrinterEnumerator = NS_STATIC_CAST(nsISimpleEnumerator*, printerListEnum)); <timeless> is that cast needed? <timeless> NS_IMETHODIMP nsPrintOptions::CreatePrintSettings(nsIPrintSettings **_retval) <timeless> { <timeless> + NS_ENSURE_ARG_POINTER(_retval); <timeless> i think we're not ensuring pointers for outs <timeless> NS_ENSURE_TRUE -> NS_ENSURE_SUCCESS in some places <timeless> sprintf(str, "%6.2f", aVal); -> snprintf All of timeless's comments were addressed; most notably I've added an Init() method, and made its existence known amongst class factories that inherent the class, as well as the other consumers.
Assignee | ||
Updated•19 years ago
|
Attachment #186174 -
Attachment is obsolete: true
Attachment #186364 -
Flags: review?(timeless)
Assignee | ||
Comment 9•19 years ago
|
||
Attachment #186175 -
Attachment is obsolete: true
Assignee | ||
Updated•19 years ago
|
Attachment #186364 -
Flags: review?(timeless)
Assignee | ||
Comment 10•19 years ago
|
||
Let's do it right this time..
Attachment #186364 -
Attachment is obsolete: true
Attachment #186376 -
Flags: review?(timeless)
Assignee | ||
Comment 11•19 years ago
|
||
Attachment #186365 -
Attachment is obsolete: true
Assignee | ||
Comment 12•19 years ago
|
||
This patch addresses further comments from timeless, most notably the following: * sDefaultFont is no longer declared static, so permanent storage is no longer required for it. However, the caller of GetDefaultFont() deletes the retrieved font after using it, without setting the pointer to nsnull. Then, our class would attempt to delete it a second time upon destruction, which would cause a crash. The patch therefore includes a small change to layout/generic/nsSimplePageSequence.cpp, which makes the caller nulls out the pointer to our default font. Arguably the caller should not be deleting it at all, but that's a subject for another bug. * My usage of NS_ENSURE_ARG was replaced by NS_ENSURE_ARG_POINTER, because it is more appropriate. * Init() was declared virtual. * ShowPrintSetupDialog() now has better error checking, an unused nsCOMPtr and an unneeded assertion were removed.
Assignee | ||
Updated•19 years ago
|
Attachment #186376 -
Attachment is obsolete: true
Attachment #186425 -
Flags: review?(timeless)
Assignee | ||
Updated•19 years ago
|
Attachment #186376 -
Flags: review?(timeless)
Assignee | ||
Comment 13•19 years ago
|
||
Attachment #186377 -
Attachment is obsolete: true
Assignee | ||
Comment 14•19 years ago
|
||
This patch adds trivial changes such as slightly better error handling and some more whitespace cleanups.
Attachment #186425 -
Attachment is obsolete: true
Attachment #186866 -
Flags: review?(timeless)
Assignee | ||
Comment 15•19 years ago
|
||
Attachment #186426 -
Attachment is obsolete: true
Assignee | ||
Updated•19 years ago
|
Attachment #186425 -
Flags: review?(timeless)
Reporter | ||
Comment 16•19 years ago
|
||
Comment on attachment 186867 [details] [diff] [review] cleanup patch, revision 2.1 (diff -w) >Index: gfx/src/nsPrintOptionsImpl.cpp >@@ -340,854 +335,931 @@ const char* nsPrintOptions::GetPrefName( > * This will read in the generic prefs (not specific to a printer) > * or it will it can read the prefs in using the printer name to qualify "or it will it can" ?! >+nsPrintOptions::AvailablePrinters(nsISimpleEnumerator **aPrinterEnumerator) >+ nsCOMPtr<nsPrinterListEnumerator> printerListEnum = >+ new nsPrinterListEnumerator(); nsCOMPtr was not designed for non interface creatures, i believe you want nsRefPtr. >+nsPrintOptions::WriteInchesFromTwipsPref(const char * aPrefId, nscoord aTwips) > { > nsAutoString inchesStr; > char * str = ToNewCString(inchesStr); > if (str) { > mPrefBranch->SetCharPref(aPrefId, str); doesn't this leak str? :) >Index: gfx/src/nsPrintOptionsImpl.h >+class NS_GFX nsPrintOptions : public nsIPrintOptions, public >+ nsIPrintSettingsService >+ * method Init >+ * Initializes member variables. Every consumer that does manual >+ * addref'ing needs to call this method! -indicate when and how often- i think you mean manual creation instead of do_CreateInstance. >+ * @return nsresult error code normally we'd list out params as @returns >+ virtual nsresult Init(); >+ * method WritePrefString >+ * Writes PRUnichar* to Prefs and deletes the contents of aString >+ nsresult WritePrefString(const char * aPrefId, const nsAString& aString);
Assignee | ||
Comment 17•19 years ago
|
||
Address comments.
Attachment #186866 -
Attachment is obsolete: true
Attachment #186913 -
Flags: review?(timeless)
Assignee | ||
Updated•19 years ago
|
Attachment #186866 -
Flags: review?(timeless)
Assignee | ||
Comment 18•19 years ago
|
||
Attachment #186867 -
Attachment is obsolete: true
Attachment #186913 -
Flags: superreview?(rbs)
Attachment #186913 -
Flags: review?(timeless)
Attachment #186913 -
Flags: review+
Comment 19•19 years ago
|
||
Comment on attachment 186913 [details] [diff] [review] cleanup patch, revision 2.2 (diff -u) I am not interested in super-reviewing this, I don't see much value in such an invasive cleanup. It messes the bonsai records for little gain.
Attachment #186913 -
Flags: superreview?(rbs)
Assignee | ||
Comment 20•19 years ago
|
||
Comment on attachment 186913 [details] [diff] [review] cleanup patch, revision 2.2 (diff -u) I'll ask bz, in that case.. I <think> he would be willing to do it when he has time.
Attachment #186913 -
Flags: superreview?(bzbarsky)
Comment 21•19 years ago
|
||
Comment on attachment 186914 [details] [diff] [review] cleanup patch, revision 2.2 (diff -w) nsAutoString inchesStr; inchesStr.AppendFloat(inches); + mPrefBranch->SetCharPref(aPrefId, NS_ConvertUTF16toUTF8(inchesStr).get()); OK, why does this use an nsAutoString instead of an nsCAutoString at all? nsSharedPageData::~nsSharedPageData() + mHeadFootFont = nsnull; why bother? (note that the other Free calls in this function do not set the pointer to null)
Assignee | ||
Comment 22•19 years ago
|
||
(In reply to comment #21) > OK, why does this use an nsAutoString instead of an nsCAutoString at all? No particular reason. (I'll change it to nsCAutoString) > nsSharedPageData::~nsSharedPageData() > + mHeadFootFont = nsnull; > > why bother? (note that the other Free calls in this function do not set the > pointer to null) See comment #12.
Assignee | ||
Updated•19 years ago
|
Attachment #186913 -
Flags: superreview?(bzbarsky)
Assignee | ||
Comment 23•19 years ago
|
||
In this revision, I've addressed biesi's comment about ns[C]AutoString. In addition, I've removed my change to nsSimplePageSequence.cpp, seeing as leaving it out doesn't crash my build anymore. The change probably had no effect anyway, because |delete| is null safe.. At this point I don't understand why the crash was happening in the first place, but since I can't reproduce it anymore, I'm letting go of this hunk.
Attachment #186914 -
Attachment is obsolete: true
Assignee | ||
Comment 24•19 years ago
|
||
Attachment #186913 -
Attachment is obsolete: true
Attachment #188243 -
Flags: superreview?(bzbarsky)
Attachment #188243 -
Flags: review-
Assignee | ||
Updated•19 years ago
|
Attachment #188243 -
Flags: review-
Comment 25•19 years ago
|
||
It'll take me some time to get to this -- I'm still swamped with things that collected over the last month. You may want to look for someone else to superreview...
Assignee | ||
Updated•19 years ago
|
Attachment #188243 -
Flags: superreview?(bzbarsky) → superreview?(dmose)
Comment 26•19 years ago
|
||
Comment on attachment 188243 [details] [diff] [review] cleanup patch, revision 2.3 (diff -u) In general it looks good; most of my comments are nit-picking, so addressing them should be straightforward. >Index: gfx/idl/nsIPrintOptions.idl >=================================================================== >RCS file: /cvsroot/mozilla/gfx/idl/nsIPrintOptions.idl,v >retrieving revision 1.37 >diff -p -8 -u -r1.37 nsIPrintOptions.idl >--- gfx/idl/nsIPrintOptions.idl 17 Apr 2004 21:52:27 -0000 1.37 >+++ gfx/idl/nsIPrintOptions.idl 4 Jul 2005 12:07:31 -0000 >@@ -87,31 +87,32 @@ interface nsIPrintOptions : nsISupports > >- [noscript] void SetFontNamePointSize(in nsNativeStringRef aName, in PRInt32 aPointSize); >+ [noscript] void SetFontNamePointSize(in AString aName, in PRInt32 aPointSize); Since the native reference is gone, how about dropping the [noscript]? > >-[scriptable, uuid(a6cf9128-15b3-11d2-932e-00805f8add32)] >+[scriptable, uuid(d9948a4d-f49c-4456-938a-acda2c8d7741)] >+ I'm confused. Why bump the UUID on the interface after the one that has actually changed? >Index: gfx/src/nsPrintOptionsImpl.cpp >=================================================================== >RCS file: /cvsroot/mozilla/gfx/src/nsPrintOptionsImpl.cpp,v >retrieving revision 1.73 >diff -p -8 -u -r1.73 nsPrintOptionsImpl.cpp >--- gfx/src/nsPrintOptionsImpl.cpp 10 Jun 2005 22:18:16 -0000 1.73 >+++ gfx/src/nsPrintOptionsImpl.cpp 4 Jul 2005 12:07:32 -0000 > // Additional Prefs >-static const char kPrintPaperSize[] = "print_paper_size"; // this has been deprecated >+// this has been deprecated >+static const char kPrintPaperSize[] = "print_paper_size"; This makes it look a bit like the comment could apply to everything below it. Maybe just change the comment to "// deprecated" at the end of the same line? > nsPrintOptions::~nsPrintOptions() > { >- if (sDefaultFont != nsnull) { >- delete sDefaultFont; >- sDefaultFont = nsnull; >+ if (mDefaultFont) { >+ delete mDefaultFont; >+ mDefaultFont = nsnull; > } > } What's the point of setting mDefaultFont to nsnull after deleting it? You're in the destructor, so mDefaultFont is about to go away completely. >>+NS_IMETHODIMP > nsPrintOptions::ShowPrintSetupDialog(nsIPrintSettings *aPS) >+{ >+ NS_ENSURE_ARG_POINTER(aPS); >+ nsresult rv; > >- return rv; >- >+ // create a nsISupportsArray of the parameters >+ // being passed to the window >+ nsCOMPtr<nsISupportsArray> array; >+ rv = NS_NewISupportsArray(getter_AddRefs(array)); >+ NS_ENSURE_SUCCESS(rv, rv); >+ >+ nsCOMPtr<nsISupports> psSupports = do_QueryInterface(aPS); >+ NS_ASSERTION(psSupports, "PrintSettings must be a supports"); >+ >+ if (psSupports) >+ array->AppendElement(psSupports); What's the point of putting this inside an if? There's already an assertion checking to make sure that you can QI to nsISupports, and if you can't that's a bug that needs to be fixed, not something that should be checked for at runtime. >+ >+ nsCOMPtr<nsIDialogParamBlock> ioParamBlock = >+ do_CreateInstance(NS_DIALOGPARAMBLOCK_CONTRACTID, &rv); >+ NS_ENSURE_SUCCESS(rv, rv); >+ >+ ioParamBlock->SetInt(0, 0); >+ >+ nsCOMPtr<nsISupports> blkSupps = do_QueryInterface(ioParamBlock); >+ NS_ASSERTION(blkSupps, "IOBlk must be a supports"); >+ if (blkSupps) >+ array->AppendElement(blkSupps); Same question. >+NS_IMETHODIMP >+nsPrintOptions::AvailablePrinters(nsISimpleEnumerator **aPrinterEnumerator) > { >- NS_ENSURE_ARG_POINTER(aPrinterEnumerator); >- *aPrinterEnumerator = nsnull; >+ *aPrinterEnumerator = nsnull; > >- nsCOMPtr<nsPrinterListEnumerator> printerListEnum = new nsPrinterListEnumerator(); >- NS_ENSURE_TRUE(printerListEnum.get(), NS_ERROR_OUT_OF_MEMORY); >+ nsRefPtr<nsPrinterListEnumerator> printerListEnum = >+ new nsPrinterListEnumerator(); >+ NS_ENSURE_TRUE(printerListEnum, NS_ERROR_OUT_OF_MEMORY); > >- nsresult rv = printerListEnum->Init(); >- if (NS_SUCCEEDED(rv)) { >- *aPrinterEnumerator = NS_STATIC_CAST(nsISimpleEnumerator*, printerListEnum); >- NS_ADDREF(*aPrinterEnumerator); >- } >- return rv; >+ NS_ADDREF(*aPrinterEnumerator = printerListEnum); >+ >+ nsresult rv = printerListEnum->Init(); >+ if (NS_FAILED(rv)) >+ NS_RELEASE(*aPrinterEnumerator); >+ >+ return rv; Instead of calling Init() after the AddRef, call it before. Furthermore, you can avoid unnecessary pointer dereferences by doing the assignment to the out param at the very end using the form: NS_ADDREF(*aPrinterEnumerator = printerListEnum.get()) > >-NS_IMETHODIMP nsPrintOptions::DisplayJobProperties( const PRUnichar *aPrinter, nsIPrintSettings* aPrintSettings, PRBool *aDisplayed) >+NS_IMETHODIMP >+nsPrintOptions::DisplayJobProperties(const PRUnichar *aPrinter, >+ nsIPrintSettings* aPrintSettings, >+ PRBool *aDisplayed) > { >- NS_ENSURE_ARG(aPrinter); >- *aDisplayed = PR_FALSE; >+ NS_ENSURE_ARG_POINTER(aPrinter); >+ *aDisplayed = PR_FALSE; >+ >+ nsresult rv; >+ nsCOMPtr<nsIPrinterEnumerator> propDlg; > >- nsresult rv; >- nsCOMPtr<nsIPrinterEnumerator> propDlg; >+ propDlg = do_CreateInstance(kCPrinterEnumerator, &rv); >+ NS_ENSURE_SUCCESS(rv, rv); > >- propDlg = do_CreateInstance(kCPrinterEnumerator, &rv); >- if (NS_FAILED(rv)) >- return rv; >+ NS_ENSURE_ARG_POINTER(aPrintSettings); >+ rv = propDlg->DisplayPropertiesDlg((PRUnichar*)aPrinter, aPrintSettings); Prefer C++ style casts to C-style casts, since they express intent more precisely and thus allow the compiler to catch more bugs at build time. In this case, NS_CONST_CAST is what you want. >-/* [noscript] voidPtr GetNativeData (in short aDataType); */ > NS_IMETHODIMP nsPrintOptions::GetNativeData(PRInt16 aDataType, void * *_retval) > { >- NS_ENSURE_ARG_POINTER(_retval); > *_retval = nsnull; >- > return NS_ERROR_NOT_IMPLEMENTED; > } Might as well get rid of the |*retval = nsnull| line here; you're already returning an error, so you don't need to guarantee that *retval is set to anything in particular. > nsresult nsPrintOptions::_CreatePrintSettings(nsIPrintSettings **_retval) > { > nsresult rv = NS_OK; >+ *_retval = nsnull; The above line shouldn't be necessary; see previous comment. There seem to be more instances of this pattern throughout the patch. None should be necessary and just waste cycles. >- nsPrintSettings * printSettings = new nsPrintSettings(); // does not initially ref count >+ // does not initially ref count >+ nsPrintSettings * printSettings = new nsPrintSettings(); > NS_ENSURE_TRUE(printSettings, NS_ERROR_OUT_OF_MEMORY); > > NS_ADDREF(*_retval = printSettings); // ref count >- InitPrintSettingsFromPrefs(*_retval, PR_FALSE, nsIPrintSettings::kInitSaveAll); // ignore return value >+ InitPrintSettingsFromPrefs(*_retval, PR_FALSE, >+ nsIPrintSettings::kInitSaveAll); >+ // ignore return value A good way to indicate that a return value is intentionally ignore is simply to cast the call itself to void. > return rv; > } > >-/* nsIPrintSettings CreatePrintSettings (); */ > NS_IMETHODIMP nsPrintOptions::CreatePrintSettings(nsIPrintSettings **_retval) > { >+ *_retval = nsnull; > return _CreatePrintSettings(_retval); > } What's the point of having this split into two functions? Why not just move all the code in _CreatePrintSettings here? >+nsresult >+nsPrintOptions::ReadPrefString(const char * aPrefId, nsAString& aString) > { > NS_ENSURE_STATE(mPrefBranch); >+ NS_ENSURE_ARG_POINTER(aPrefId); >+ > char * str = nsnull; > nsresult rv = mPrefBranch->GetCharPref(aPrefId, &str); >- if (NS_SUCCEEDED(rv) && str) { >- CopyUTF8toUTF16(str, aString); >- nsMemory::Free(str); >+ if (NS_SUCCEEDED(rv)) { >+ // By encapsulating str, we save copying and freeing it >+ aString = nsDependentString((NS_ConvertUTF8toUTF16(str))); > } > return rv; > } The above code will leak, because str itself is never freed. Since NS_ConvertUTF8toUTF16 is itself implicitly copying the string into a stack variable, there's no real savings there either. Additionally, this code is attempting to return a string dependant on a stack variable which is about to go out of scope. Either this is going to force a second copy, or else you'll have a bug; I'm not sure which. I'd vote with leaving this function that way it was before. >+void >+nsPrintOptions::WriteInchesFromTwipsPref(const char * aPrefId, nscoord aTwips) > { >- if (!mPrefBranch) { >+ if (!mPrefBranch) > return; >- } Why get rid of the braces here? It's an invitation to a future error if someone decides to add some other piece of code to the else clause but forgets to add them back.
Attachment #188243 -
Flags: superreview?(dmose) → superreview-
Comment 27•19 years ago
|
||
>+ aString = nsDependentString((NS_ConvertUTF8toUTF16(str)));
yeah, that should absolutely stay with CopyUTF8toUTF16. I'm surprised that you
can construct an nsDependentString like that...
maybe that function should also use nsXPIDLCString.
Assignee | ||
Comment 28•19 years ago
|
||
This patch addresses dmose's comments.
Attachment #188243 -
Attachment is obsolete: true
Attachment #189056 -
Flags: superreview?(dmose)
Assignee | ||
Updated•19 years ago
|
Attachment #189056 -
Flags: superreview?(dmose)
Assignee | ||
Comment 29•19 years ago
|
||
The right patch this time.
Attachment #189056 -
Attachment is obsolete: true
Assignee | ||
Comment 30•19 years ago
|
||
Attachment #188241 -
Attachment is obsolete: true
Assignee | ||
Updated•19 years ago
|
Attachment #189059 -
Flags: superreview?(dmose)
Assignee | ||
Comment 31•19 years ago
|
||
timeless mentioned that when removing [noscript], I should switch from InitialCaps to interCaps.
Attachment #189059 -
Attachment is obsolete: true
Attachment #189307 -
Flags: superreview?(dmose)
Assignee | ||
Updated•19 years ago
|
Attachment #189059 -
Flags: superreview?(dmose)
Assignee | ||
Comment 32•19 years ago
|
||
Attachment #189060 -
Attachment is obsolete: true
Comment 33•19 years ago
|
||
Comment on attachment 189307 [details] [diff] [review] cleanup patch, revision 2.5.1 (diff -u) sr=dmose
Attachment #189307 -
Flags: superreview?(dmose) → superreview+
Assignee | ||
Updated•19 years ago
|
Attachment #189307 -
Flags: approval1.8b4?
Updated•19 years ago
|
Attachment #189307 -
Flags: approval1.8b4? → approval1.8b4+
Assignee | ||
Comment 34•19 years ago
|
||
Checked in by timeless (2005-07-19 14:55). Thanks guys!
Status: ASSIGNED → RESOLVED
Closed: 19 years ago
Resolution: --- → FIXED
Comment 35•19 years ago
|
||
This caused a bunch of issues on Mac; see bug 306370.
Updated•13 years ago
|
Crash Signature: [@ nsPrintOptions::_CreatePrintSettings]
You need to log in
before you can comment on or make changes to this bug.
Description
•