This is an archived page. It's not actively maintained.

Using the Mac OS X leaks tool

Mac OS X comes with a tool called leaks.  You can use this tool to determine the allocated memory buffers inside a program to which no existing pointer (anywhere in the stack or registers) points.  This is useful to determine possible leaks in Firefox, for example.

Here are some tips on how to use this tool more effectively.

Getting stack traces for allocation points

leaks is capable of showing the stack trace where a leaked memory buffer was allocated.  To get stack reports, run Firefox with the MallocStackLogging environment variable set.

Avoiding false positives

A lot of places in Gecko, we store masked pointers to allocated buffers.  For example, we might have code like this:

Type* foo = new Foo();
foo = reinterpret_cast<Type*> (static_cast<unsigned> (foo | 0x1));

// Later on, when we want to use foo
Type* real = reinterpret_cast<Type*> (static_cast<unsigned> (foo) & ~0x1);

In the above example, we can use the least significant bit to store a flag, for example.  Doing this causes the memory address stored in foo to not be mappable to any allocated block.

Unfortunately, leaks is not smart to detect these types of allocations, so you can use the -exclude argument to ask it to ignore some allocations.  The following is a command line I came up with which removes most of the false positives when running leaks on Firefox:

leaks -exclude GetPropertyTreeChild -exclude js_NewRegExp -exclude InitExnPrivate -exclude 'CSSParserImpl::ParseStyleAttribute(nsAString_internal const&, nsIURI*, nsIURI*, nsIPrincipal*, nsICSSStyleRule**)' -exclude 'nsAttrValue::ParseAtomArray(nsAString_internal const&)' -exclude define_JavaPackage -exclude 'nsAttrValue::EnsureEmptyMiscContainer()' -exclude 'nsRuleNode::ConvertChildrenToHash()' -exclude 'nsRuleNode::Sweep()' -exclude 'nsXULDocument::AddBroadcastListenerFor(nsIDOMElement*, nsIDOMElement*, nsAString_internal const&)' -exclude 'nsRuleNode::Transition(nsIStyleRule*, unsigned char, unsigned char)' -exclude ProcessCharSet -exclude 'js::PropertyTree::insertChild(JSContext*, js::Shape*, js::Shape*)' -exclude 'nsXBLProtoImplMethod::AppendBodyText(nsAString_internal const&)' -exclude 'nsCSSExpandedDataBlock::Compress(nsCSSCompressedDataBlock**, nsCSSCompressedDataBlock**)' -exclude 'nsHtml5Portability::newStringFromBuffer(unsigned short*, int, int)' -exclude 'gfxMacFont::CreatePlatformShaper()' -exclude 'PICLinker::init(JSContext*)' -exclude 'js::PropertyTree::removeChild(js::Shape*)' -exclude 'NewArguments(JSContext*, JSObject*, unsigned int, JSObject&)' -exclude 'nsAlertsService::Init()' -exclude 'nsXULPrototypeElement::SetAttrAt(unsigned
int, nsAString_internal const&, nsIURI*)' -exclude 'nsStyledElement::ParseStyleAttribute(nsAString_internal const&, nsAttrValue&, int)' -exclude 'CSSStyleRuleImpl::DeclarationChanged(mozilla::css::Declaration*, int)' -exclude 'nsIDOMCSS2Properties_Set(JSContext*, JSObject*, long, int, nsCSSProperty, unsigned long long*)' -exclude 'TryToStartImageLoad(nsCSSValue const&, nsIDocument*, nsCSSProperty)' -exclude 'nsIDOMCSSStyleDeclaration_SetCssText(JSContext*, JSObject*, long, int, unsigned long long*)' -exclude 'nsAttrValue::ToString(nsAString_internal&) const' -exclude 'nsAttrValue::ToString(nsAString_internal&) const' -exclude 'js_NewFlatClosure(JSContext*, JSFunction*, JSOp, unsigned long)' -exclude 'nsXBLProtoImplMethod::SetLineNumber(unsigned int)' -exclude 'nsXBLProtoImplMethod::AddParameter(nsAString_internal const&)' -exclude TSMCurrentKeyboardInputSourceRefCreate -exclude 'nsCheapStringSet::Put(nsAString_internal const&)' <pid>

Note that you should enter this while command in a single line, and replace <pid> with the PID of the Firefox process. Click here to download a plain text copy of the command.