Up to: Mika Raento's Symbian Programming pages

Symbian Programming - Debugging memory leaks

3rd edition

The best way to debug memory leaks on 3rd edition is to use Symbian's HookLogger tool as it allows you to dump the callstack for the leaked allocation after you've seen the panic.

If you do have a repeatable panic address and hooklogger is not working for you, you can override the default allocator and set a breakpoint in your own code. See An example custom allocator.

1st/2nd edition

If you fail to free memory in an application running on the emulator, the application framework will raise a panic on exit. The panic tells you which memory cell wasn't freed, but translating this into an allocation takes a bit more work. The steps here are based on the Symbian Knowledge base article FAQ-0488.

The easier method

A somewhat easier way than the one detailed below is the following:

  1. Note the hexadecimal address you get with the ALLOC panic.
  2. Put a breakpoint somewhere in your app before the memory gets allocated (this might require some guessing).
  3. After hitting this breakpoint, add a data breakpoint via Edit|Breakpoints|Data and write 0x<<Panic address> in the 'Enter expression to be evaluated' box and '4' in the 'Enter number of elements...' box.
  4. If you get an 'cannot set breakpoint' error that memory region is not in use yet. Move your original breakpoint further down your application and try again.
  5. Now the program should stop when you allocate the leaked memory, but it may stop before as well if the memory gets reused. In that case just continue until you hit the actual allocation.

The more tedious method

So you got your Panic ALLOC. After the panic you get two numbers (the second one is 0). These are printed in a panic dialog on the emulator, as well as in the debug message pane in VC++. The first number is the address of the leaked memory cell. What we want to do is find where the memory was allocated.

Memory allocations happen in User::Alloc. We want to put a breakpoint at the end of the function to see when the offending cell is allocated. This isn't trivial, since there are no debug symbols or code for the library. What you have to do is:

  1. Find the exported function ordinal in EUSER.LIB by running dumpbin /exports EUSER.LIB in \symbian\6.1\Series60\Epoc32\Release\wins\UDEB and looking for the User::Alloc(int). The first number in the output row is the ordinal. For my Series 60 SDK 1.0 this is 345.
  2. Find the function offset in the EUSER.DLL by running dumpbin /exports EUSER.DLL and looking for the ordinal you found in the previous step (342). For me this gives offset 0000109B.
  3. In VC++ start the emulator (don't start your app yet).
  4. Go to Debug|Modules and look up the address EUSER.DLL is loaded at (for me 0x60000000.
  5. Add the offset you got at step 2 to the load address, I get 6000109B. Put a breakpoint there and start your app.
  6. Switch to the emulator and start your app, it should stop at the breakpoint. Follow the disassembly from the initial jmp. Now you are at the actually function (they seem to use incremental linking). In my dll, this is at 0x6002D80B.
  7. Find the next ret statement beginning from the point you are at. Set a breakpoint there. For me this is at 0x60033ACD.
  8. Go to Edit|Breakpoints. Remove the first breakpoint you set, and add the condition (EAX==<YOUR ALLOC PANIC ADDRESS>) to the second one.

Now continue your application, and it should break at the point where you are allocating the cell.

If you think the steps 1--5 are too complicated, you can find the function address in another way as well:

  1. Put a call to User::Alloc() in your code.
  2. Put a breakpoint on that line
  3. Hit the breakpoint, step into the function once (now you are in the link jump table in your app) and twice (now you are at the EUSER.DLL initial jmp).
  4. Continue from step 6 above

Mika Raento, mikie(at)iki.fi