Skip to content

Conversation

pjurczynski
Copy link

@pjurczynski pjurczynski commented Jul 24, 2025

What

Addresses: #374

targets a TypeError "TypeError: Cannot read properties of undefined (reading 'offset')" that was happening when:

  • a slice read was equal to a block size
  • reading last part of the data

Details

The fix removes the "one-off" bug:

  • Top is the first byte of the next block that we don't want to read.
  • The last block we want to read (blockIdHigh) is found by knowing the last byte we want to read and divide it by the block size.

Test improvements:

  • Moved blockedSource declaration inside each test for better isolation. (BlockedSource is stateful)

targets a TypeError "TypeError: Cannot read properties of undefined (reading 'offset')" that was happening when:
- a slice read was equal to a block size
- reading last part of the data

The fix removes the "one-off" bug:
- top is the first byte of the next block that we don't want to read.
- The last block we want to read (blockIdHigh) is found by knowing the last byte we want to read and divide it by the block size.

   - Moved blockedSource declaration inside each test for better isolation. (BlockedSource is stateful)
}
const blockIdLow = Math.floor(slice.offset / this.blockSize);
const blockIdHigh = Math.floor(top / this.blockSize);
const blockIdHigh = Math.floor((top - 1) / this.blockSize);
Copy link

@turien-pix4d turien-pix4d Aug 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR mention the bug was occurring when reading the last block and the blockSize is equals to slice.length.
For what I see, this change may also affect the behavior of reading the first block.

In a situation where slice.offset is 0 and blockSize is equals to slice.length, for the previous implementation, blockIdHigh would have a value of 1, with the new implementation it will have a value of 0.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's a great observation! It is a bug as well. It was documented with a test at https://github.com/geotiffjs/geotiff.js/pull/474/files#diff-492ba43e11ce778a6c52157c7795c3a45b40213fb11b00df31dbb469614b4bd1R1325-R1335

In case you describe, our data would fit exactly in one block - blockId 0.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've generalized this case in the description as reading a block that is equal to a block size (so originally the code would also fail if you try to read offset 2, blockSize 2 and slice length 2.. etc.)

@jjimenezshaw
Copy link

Is there anything else needed to merge this PR?

@jjimenezshaw
Copy link

What else is needed?
fyi @TheMrCam

Copy link
Collaborator

@TheMrCam TheMrCam left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, although I haven't dug too deep into this bug or the BlockedSource itself. I have more of a question than comment about one test, but otherwise this worked for me in quick npm pack downstream check.

const blockedSource = new BlockedSource(null, { blockSize: 2 });
blockedSource.source = { fileSize: null, fetch: async () => [{ data: new Uint8Array(2).buffer, offset: 0 }] };
const data = await blockedSource.fetch([{ offset: 0, length: 2 }]);
expect(data[0].byteLength).to.equal(2);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this it testing? To me, this kind of looks like

new Uint8Array(2).byteLength === 2

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I should reword the title to Fetches all data in a single block?

new Uint8Array(2).byteLength === 2

it is like so, but jus as a coincidence. It equals 2 not because we defined a fetch like so, but because we did blockedSource.fetch([{...length: 2 }]).

(it also fails without the fix from the PR)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh okay makes sense, thank you! Yeah I think Fetches all data in a single block would make it a bit more clear, but it's not a huge deal either way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bugfix Fixes a bug
Projects
None yet
Development

Successfully merging this pull request may close these issues.

TypeError: Cannot read properties of undefined (reading 'offset')
4 participants