Repository navigation
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configuration
📒 Files selected for processing (4)
Included review availability: This review used your included allowance. Your plan provides up to 2 included reviews per hour; 1 remain after this review. 📝 WalkthroughWalkthroughThe pure Python reader and C extension update search-tree validation, IPv4 and IPv6 network iteration, and iterator exhaustion behavior. Tests cover malformed trees, pointer bounds, IPv6 network boundaries, and iterator errors. ChangesReader integrity and iteration
Priority: ➖ Normal Estimated code review effort: 3 (Moderate) | ~25 minutes Change: Bug fix Suggested reviewers: Merge Risk: ⚪ Minimal · up to No concrete merge-blocking issue remains in the reviewed reader and iterator changes. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Full details: Docstring CoverageExplanation Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 25 functions across 4 files. (1 skipped: 1 unsupported.)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. A rabbit checks the branching tree Comment |
19c4250 to
788c36c
Compare
3ab7b3c to
432eaed
Compare
788c36c to
4b038aa
Compare
432eaed to
107c356
Compare
107c356 to
f8fd2ab
Compare
4b038aa to
ca0e3e2
Compare
f8fd2ab to
84e08a9
Compare
ca0e3e2 to
8bc9b74
Compare
84e08a9 to
0c2b173
Compare
8bc9b74 to
ed0485d
Compare
0c2b173 to
a816889
Compare
a816889 to
36af132
Compare
da21457 to
e56d8aa
Compare
fda9ed0 to
5642dcb
Compare
e56d8aa to
d21dd5d
Compare
5642dcb to
1a2020d
Compare
1a2020d to
28a2e5f
Compare
d21dd5d to
34161ac
Compare
a5282b1 to
47376c5
Compare
reader_iter_next checked for a closed reader before it checked whether the iterator had ended. After close(), an exhausted iterator raised ValueError instead of StopIteration, which breaks the iterator protocol. The pure Python iterator, a generator, stops as expected. Mark the iterator as done when next() raises StopIteration, and check that flag first. It needs no lock, because the flag belongs to the iterator. The list of pending records cannot replace the flag: it is already empty when the last record is returned, and the next call must still report a closed or reopened reader, as the pure Python iterator does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
34161ac to
458321c
Compare
Neither reader limited the depth of the tree walk during iteration. A corrupt tree, such as one where a node points back to itself, made the C extension set bits past the end of the 16-byte ip_packed array, and then past its heap allocation. The process aborted with heap corruption. The pure Python reader recursed until it raised RecursionError, which a caller that catches InvalidDatabaseError does not catch. A node at the full address depth has no valid children, so both readers now raise InvalidDatabaseError when they reach one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
After an error, such as a corrupt search tree, the C iterator kept its pending records, and the next call continued from them. With a cycle in the tree, a caller that skipped bad records could get many errors before StopIteration. The pure Python iterator is a generator, so it stops after its first error. Free the pending records and mark the iterator done when next() fails, so the C iterator stops too. Reuse the loop from ReaderIter_dealloc as free_records. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Both iterators turned any network whose first 96 bits were zero into an IPv4 network and subtracted 96 from its prefix length. For a network shorter than /96, such as ::/1, the prefix length became negative, and iteration raised ValueError. An IPv4 network in an IPv6 tree is at least /96, so convert only those. The pure Python iterator had two more bugs here. It compared the address with 2**32 using <=, so ::1:0:0/96 got a prefix length of 0 and raised ValueError. It also skipped every data record equal to the IPv4 start node, although only a search node can be the IPv4 subtree. Use <, and skip only a search node, as the C iterator does. Build the network with IPv4Network or IPv6Network, because ip_network() picks IPv4 for any small integer. Its alias rule also differed from the C iterator. It skipped the IPv4 start node in an IPv4 tree, where a record that points back to the root is a cycle, and inside the IPv4 subtree of an IPv6 tree. Both hid a corrupt tree behind partial results. Skip the subtree only when an address with a set bit in its first 96 bits leads to it, as the C iterator does, and raise InvalidDatabaseError for a record that points to the root, which libmaxminddb treats as invalid. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
_resolve_data_pointer checked only that a data pointer was inside the
buffer. A search tree record that pointed into the 16-byte separator
between the search tree and the data section decoded the zero bytes
there, so get() returned {} and iteration yielded the network with {}.
libmaxminddb rejects such a record as a corrupt search tree.
Reject a pointer before the start of the data section too. A lookup
benchmark showed no measurable cost.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
458321c to
2989384
Compare
Fixes iteration over corrupt and unusual search trees in both readers.
RecursionError, or returned part of the networks. Both now raiseInvalidDatabaseErrorat a node at the full address depth or a record that points to the root.::/1got a negative prefix length and raisedValueError. Only a /96 or longer network converts now. The pure Python reader also skipped data records equal to the IPv4 start node, mis-compared::1:0:0/96, and treated a cycle inside the IPv4 subtree as an alias. It now follows the C iterator.ValueErrorinstead ofStopIterationwhen it was exhausted and its reader closed, and it continued after an error. It now stops after any error, including an error in one record's data, as the pure Python generator does.{}for a record that points into the 16-byte separator before the data section. It now raisesInvalidDatabaseError.The C and pure Python iterators give the same networks on every test database. A pure Python lookup benchmark showed no measurable change.
STF-1959
🤖 Generated with Claude Code
Summary by CodeRabbit
InvalidDatabaseErrorin applicable cases instead of returning incomplete results or causing recursion errors.