Opened 12 years ago

Closed 12 years ago

#8123 closed bug (fixed)

PANIC: object_cache: tried to free invalid object pointer

Reported by: beos_zealot Owned by: axeld
Priority: normal Milestone: R1
Component: System/Kernel Version: R1/Development
Keywords: slab deadbeef Cc:
Blocked By: Blocking:
Platform: x86

Description

Updated local Haiku SVN repository and started building anyboot image:
jam -j2 -q @anyboot

after several minutes of building I got PANIC (attached pic: PANIC - object_cache - tried to free invalid object pointer.jpg)

Haiku gcc4 hrev43224
Intel Core 2
2 GB RAM (swap on)

Attachments (4)

PANIC - object_cache - tried to free invalid object pointer.jpg (737.5 KB ) - added by beos_zealot 12 years ago.
deadbeef.jpg (397.7 KB ) - added by beos_zealot 12 years ago.
reproduce.patch (860 bytes ) - added by ahenriksson 12 years ago.
check_unused.patch (1.4 KB ) - added by ahenriksson 12 years ago.

Download all attachments as: .zip

Change History (11)

comment:1 by bonefish, 12 years ago

Keywords: slab deadbeef added; PANIC object_cache tried to free invalid object pointer removed
Owner: changed from axeld to mmlr
Status: newassigned

Maybe mmlr is interested in looking into that. The stack trace suggests that the magazine that is being emptied was already freed.

by beos_zealot, 12 years ago

Attachment: deadbeef.jpg added

comment:2 by beos_zealot, 12 years ago

Second time encountered same PANIC (attached image: deadbeef.jpg) while building Haiku anyboot image.

Haiku gcc4 hrev43751

by ahenriksson, 12 years ago

Attachment: reproduce.patch added

by ahenriksson, 12 years ago

Attachment: check_unused.patch added

comment:3 by ahenriksson, 12 years ago

patch: 01

comment:4 by ahenriksson, 12 years ago

I've encountered this as well, or at least something very similar. The problem is in the block cache, when a cached_block with is_dirty = true, discard = false, transaction = NULL and ref_count = 0 is added to the unused_blocks list. This can happen when a transaction is aborted, or when the block cache is used without a transaction.

When RemoveUnusedBlocks() free's a block with these properties, it will call BlockWriter::WriteBlock(), which eventually leads to the block being re-added to the list in _BlockDone(). When execution returns to RemoveUnusedBlocks(), the block is free'd. So at this point we have a free'd block in the unused_blocks list, waiting to cause a crash.

reproduce.patch contains code to reproduce the crash, and check_unused.patch is my attempt at fixing the problem. As far as I can tell, cached_block::unused basically means "is this block in unused_list", so checking for that tells _BlockDone() that it was called from RemoveUnusedBlocks() and should not re-add the block.

comment:5 by anevilyak, 12 years ago

Owner: changed from mmlr to axeld

comment:6 by axeld, 12 years ago

Great findings! Actually, your patch is not entirely correct, even though it helps ignoring the problem: when a block is without a transaction, it mustn't be dirty anymore.

It looks both cache_abort_transaction(), and cache_abort_sub_transaction() don't deal with this correctly. The latter even has some more problems, as it does not reset the transaction field when it should.

I'm currently working on a revised patch. Thanks a lot in any case!

comment:7 by axeld, 12 years ago

Resolution: fixed
Status: assignedclosed

Applied your patch in hrev44355 - please use git format-patch next time, as this makes it easier to attribute the change to you. I've made the additional changes in hrev44357 which hopefully solves the underlying issue.

Note: See TracTickets for help on using tickets.