BFS: Propagate errors from CachedNode::InternalSetTo properly.
Otherwise, SetTo() might return B_OK when fNode is really NULL, leading to crashes later when something tries to use the block. Fixes #14762.
This commit is contained in:
@@ -314,7 +314,11 @@ CachedNode::SetTo(off_t offset, const bplustree_node** _node, bool check)
|
|||||||
RETURN_ERROR(B_BAD_VALUE);
|
RETURN_ERROR(B_BAD_VALUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (InternalSetTo(NULL, offset) != NULL && check) {
|
status_t status = InternalSetTo(NULL, offset);
|
||||||
|
if (status != B_OK)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
if (check) {
|
||||||
// sanity checks (links, all_key_count)
|
// sanity checks (links, all_key_count)
|
||||||
if (!fTree->fHeader.CheckNode(fNode)) {
|
if (!fTree->fHeader.CheckNode(fNode)) {
|
||||||
FATAL(("invalid node [%p] read from offset %" B_PRIdOFF " (block %"
|
FATAL(("invalid node [%p] read from offset %" B_PRIdOFF " (block %"
|
||||||
@@ -349,7 +353,10 @@ CachedNode::SetToWritable(Transaction& transaction, off_t offset, bool check)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (InternalSetTo(&transaction, offset) != NULL && check) {
|
if (InternalSetTo(&transaction, offset) != B_OK)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (check) {
|
||||||
// sanity checks (links, all_key_count)
|
// sanity checks (links, all_key_count)
|
||||||
if (!fTree->fHeader.CheckNode(fNode)) {
|
if (!fTree->fHeader.CheckNode(fNode)) {
|
||||||
FATAL(("invalid node [%p] read from offset %" B_PRIdOFF " (block %"
|
FATAL(("invalid node [%p] read from offset %" B_PRIdOFF " (block %"
|
||||||
@@ -420,15 +427,20 @@ CachedNode::SetToWritableHeader(Transaction& transaction)
|
|||||||
#endif // !_BOOT_MODE
|
#endif // !_BOOT_MODE
|
||||||
|
|
||||||
|
|
||||||
bplustree_node*
|
status_t
|
||||||
CachedNode::InternalSetTo(Transaction* transaction, off_t offset)
|
CachedNode::InternalSetTo(Transaction* transaction, off_t offset)
|
||||||
{
|
{
|
||||||
|
if (offset >= fTree->fStream->Size()) {
|
||||||
|
Unset();
|
||||||
|
RETURN_ERROR(B_BAD_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
off_t fileOffset;
|
off_t fileOffset;
|
||||||
block_run run;
|
block_run run;
|
||||||
if (offset >= fTree->fStream->Size()
|
status_t status = fTree->fStream->FindBlockRun(offset, run, fileOffset);
|
||||||
|| fTree->fStream->FindBlockRun(offset, run, fileOffset) != B_OK) {
|
if (status != B_OK) {
|
||||||
Unset();
|
Unset();
|
||||||
return NULL;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !_BOOT_MODE
|
#if !_BOOT_MODE
|
||||||
@@ -461,7 +473,7 @@ CachedNode::InternalSetTo(Transaction* transaction, off_t offset)
|
|||||||
if (fBlock == NULL) {
|
if (fBlock == NULL) {
|
||||||
fBlock = (uint8*)malloc(volume->BlockSize());
|
fBlock = (uint8*)malloc(volume->BlockSize());
|
||||||
if (fBlock == NULL)
|
if (fBlock == NULL)
|
||||||
return NULL;
|
RETURN_ERROR(B_NO_MEMORY);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (read_pos(volume->Device(), newBlockNumber << volume->BlockShift(),
|
if (read_pos(volume->Device(), newBlockNumber << volume->BlockShift(),
|
||||||
@@ -483,10 +495,10 @@ CachedNode::InternalSetTo(Transaction* transaction, off_t offset)
|
|||||||
- (fileOffset + (blockOffset << volume->BlockShift())));
|
- (fileOffset + (blockOffset << volume->BlockShift())));
|
||||||
} else {
|
} else {
|
||||||
fNode = NULL;
|
fNode = NULL;
|
||||||
REPORT_ERROR(B_IO_ERROR);
|
RETURN_ERROR(B_IO_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
return fNode;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -230,7 +230,7 @@ public:
|
|||||||
bplustree_node* Node() const { return fNode; }
|
bplustree_node* Node() const { return fNode; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bplustree_node* InternalSetTo(Transaction* transaction,
|
status_t InternalSetTo(Transaction* transaction,
|
||||||
off_t offset);
|
off_t offset);
|
||||||
|
|
||||||
BPlusTree* fTree;
|
BPlusTree* fTree;
|
||||||
|
|||||||
Reference in New Issue
Block a user