Skip to content

Fix validation of empty maps/arrays at end of metadata#422

Open
oschwald wants to merge 1 commit intomainfrom
greg/eng-4322
Open

Fix validation of empty maps/arrays at end of metadata#422
oschwald wants to merge 1 commit intomainfrom
greg/eng-4322

Conversation

@oschwald
Copy link
Member

@oschwald oschwald commented Mar 3, 2026

Summary

  • Fixed an off-by-one in the map/array size validation in get_entry_data_list() (added in c1d353a) that rejected valid 0-length containers at the end of the metadata section
  • MMDB_open would return MMDB_INVALID_DATA_ERROR for databases where description (empty map) or languages (empty array) was the last metadata field
  • Changed >= to > in both the array and map bounds checks — the existing second condition already correctly handles non-empty containers at the boundary

Test plan

  • New empty_container_metadata_t test confirms both empty-map-last and empty-array-last databases open and look up successfully
  • Existing bad_data_size_t test still rejects oversized arrays/maps (DoS protection preserved)
  • Full test suite passes (26/26)

Fixes ENG-4322. Reported in vimt/MaxMind-DB-Writer-python#16.

Submodule PR: maxmind/MaxMind-DB#222

🤖 Generated with Claude Code

@gemini-code-assist
Copy link

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses a critical bug in the MaxMind DB library where databases containing empty maps or arrays as the final metadata fields were erroneously marked as invalid. The fix corrects an off-by-one error in the data section size validation, ensuring that such valid databases can now be opened and processed successfully. This improves the robustness and compatibility of the library with a broader range of MMDB files.

Highlights

  • Validation Fix: Fixed an off-by-one error in the get_entry_data_list() function's map/array size validation, which previously rejected valid 0-length containers at the end of the metadata section.
  • Database Compatibility: Resolved an issue where MMDB_open would incorrectly return MMDB_INVALID_DATA_ERROR for databases where an empty map (e.g., description) or an empty array (e.g., languages) was the last metadata field.
  • Bounds Check Adjustment: Changed the array and map bounds checks from >= to > for array_offset and offset respectively, ensuring that empty containers at the data section boundary are correctly handled.
  • New Test Case: Added a new test, empty_container_metadata_t, to specifically confirm that databases with empty maps or arrays as the last metadata fields can be opened and looked up successfully.
Changelog
  • Changes.md
    • Added a new changelog entry for version 1.13.3 describing the fix for empty map/array validation in metadata.
  • src/maxminddb.c
    • Modified array size validation from >= to > for array_offset to allow empty arrays at the end of the data section.
    • Modified map size validation from >= to > for offset to allow empty maps at the end of the data section.
  • t/CMakeLists.txt
    • Added empty_container_metadata_t to the list of tests.
  • t/Makefile.am
    • Added empty_container_metadata_t to the check_PROGRAMS list.
  • t/empty_container_metadata_t.c
    • Added a new test file to verify that MMDB files with empty maps or arrays as the last metadata fields can be opened successfully.
  • t/maxmind-db
    • Updated the MaxMind-DB submodule reference.
Activity
  • Fixed an off-by-one error in map/array size validation in get_entry_data_list().
  • Addressed an issue where MMDB_open rejected valid 0-length containers at the end of the metadata section.
  • Introduced empty_container_metadata_t test to confirm the fix.
  • Ensured existing bad_data_size_t test still rejects oversized arrays/maps.
  • Confirmed full test suite passes (26/26).
  • Fixed issue ENG-4322.
  • Reported in vimt/MaxMind-DB-Writer-python#16.
  • Submodule PR: https://github.com/maxmind/MaxMind-DB/pull/222.
  • Generated with Claude Code.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request fixes an off-by-one error in map/array size validation that incorrectly rejected valid databases with empty containers at the end of the metadata. The change correctly adjusts the boundary checks from >= to > to allow for this case. New tests are added to verify the fix for both empty maps and arrays. The changes look correct and effectively address the issue. I've added one suggestion to refactor the new test code to reduce duplication.

Comment on lines +3 to +51
void test_empty_map_last_in_metadata(void) {
char *db_file =
bad_database_path("libmaxminddb-empty-map-last-in-metadata.mmdb");

MMDB_s mmdb;
int status = MMDB_open(db_file, MMDB_MODE_MMAP, &mmdb);
cmp_ok(status,
"==",
MMDB_SUCCESS,
"opened MMDB with empty map at end of metadata");

if (status != MMDB_SUCCESS) {
diag("MMDB_open failed: %s", MMDB_strerror(status));
free(db_file);
return;
}

int gai_error, mmdb_error;
MMDB_lookup_string(&mmdb, "1.2.3.4", &gai_error, &mmdb_error);
cmp_ok(mmdb_error, "==", MMDB_SUCCESS, "lookup succeeded");

MMDB_close(&mmdb);
free(db_file);
}

void test_empty_array_last_in_metadata(void) {
char *db_file =
bad_database_path("libmaxminddb-empty-array-last-in-metadata.mmdb");

MMDB_s mmdb;
int status = MMDB_open(db_file, MMDB_MODE_MMAP, &mmdb);
cmp_ok(status,
"==",
MMDB_SUCCESS,
"opened MMDB with empty array at end of metadata");

if (status != MMDB_SUCCESS) {
diag("MMDB_open failed: %s", MMDB_strerror(status));
free(db_file);
return;
}

int gai_error, mmdb_error;
MMDB_lookup_string(&mmdb, "1.2.3.4", &gai_error, &mmdb_error);
cmp_ok(mmdb_error, "==", MMDB_SUCCESS, "lookup succeeded");

MMDB_close(&mmdb);
free(db_file);
}

Choose a reason for hiding this comment

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

medium

The two test functions test_empty_map_last_in_metadata and test_empty_array_last_in_metadata are nearly identical. To improve maintainability and reduce code duplication, you could extract the common logic into a helper function. This would make the tests cleaner and easier to manage in the future.

static void test_db_opens_and_lookups(const char *filename, const char *description) {
    char *db_file = bad_database_path(filename);

    MMDB_s mmdb;
    int status = MMDB_open(db_file, MMDB_MODE_MMAP, &mmdb);
    cmp_ok(status, "==", MMDB_SUCCESS, description);

    if (status != MMDB_SUCCESS) {
        diag("MMDB_open failed: %s", MMDB_strerror(status));
        free(db_file);
        return;
    }

    int gai_error, mmdb_error;
    MMDB_lookup_string(&mmdb, "1.2.3.4", &gai_error, &mmdb_error);
    cmp_ok(mmdb_error, "==", MMDB_SUCCESS, "lookup succeeded");

    MMDB_close(&mmdb);
    free(db_file);
}

void test_empty_map_last_in_metadata(void) {
    test_db_opens_and_lookups("libmaxminddb-empty-map-last-in-metadata.mmdb",
                              "opened MMDB with empty map at end of metadata");
}

void test_empty_array_last_in_metadata(void) {
    test_db_opens_and_lookups("libmaxminddb-empty-array-last-in-metadata.mmdb",
                              "opened MMDB with empty array at end of metadata");
}

The size validation added in c1d353a to prevent DoS via exaggerated
map/array sizes used >= when checking offset against data_section_size.
This rejected valid 0-length containers when they were the last field
in metadata (offset_to_next == data_section_size). Change to > since
the existing second condition (size > remaining) already correctly
handles the boundary case for non-empty containers.

Reported in vimt/MaxMind-DB-Writer-python#16.

ENG-4322

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@horgh
Copy link
Contributor

horgh commented Mar 4, 2026

This too, though I don't know that it especially matters (Codex this time):

  1. Low: The new regression test can produce a false positive because it only asserts mmdb_error and ignores gai_error (and the lookup result). In MMDB_lookup_string, mmdb_error
     is explicitly set to success when address parsing fails, so this test could pass without actually exercising lookup on some platforms.
      - Test site: t/empty_container_metadata_t.c:17, t/empty_container_metadata_t.c:19
      - Behavior source: src/maxminddb.c:892, src/maxminddb.c:895

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants