Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Changes.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## 1.13.3 - 2026-XX-XX

- Fixed validation of empty maps and arrays at the end of the metadata section.
`MMDB_open` would incorrectly reject databases where a 0-element map or array
was the last field in metadata. Reported in vimt/MaxMind-DB-Writer-python#16.

## 1.13.2 - 2026-02-25

- Fixed a compilation failure on macOS 26 (Tahoe) where `sys/endian.h` defines
Expand Down
4 changes: 2 additions & 2 deletions src/maxminddb.c
Original file line number Diff line number Diff line change
Expand Up @@ -1729,7 +1729,7 @@ static int get_entry_data_list(const MMDB_s *const mmdb,
uint32_t array_size = entry_data_list->entry_data.data_size;
uint32_t array_offset = entry_data_list->entry_data.offset_to_next;
/* Each array element needs at least 1 byte. */
if (array_offset >= mmdb->data_section_size ||
if (array_offset > mmdb->data_section_size ||
array_size > mmdb->data_section_size - array_offset) {
DEBUG_MSG("array size exceeds remaining data section");
return MMDB_INVALID_DATA_ERROR;
Expand Down Expand Up @@ -1758,7 +1758,7 @@ static int get_entry_data_list(const MMDB_s *const mmdb,

offset = entry_data_list->entry_data.offset_to_next;
/* Each map entry needs at least a key and a value (1 byte each). */
if (offset >= mmdb->data_section_size ||
if (offset > mmdb->data_section_size ||
size > (mmdb->data_section_size - offset) / 2) {
DEBUG_MSG("map size exceeds remaining data section");
return MMDB_INVALID_DATA_ERROR;
Expand Down
1 change: 1 addition & 0 deletions t/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ if(UNIX) # or if (NOT WIN32)
bad_data_size_t
bad_epoch_t
bad_indent_t
empty_container_metadata_t
max_depth_t
threads_t
)
Expand Down
3 changes: 2 additions & 1 deletion t/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ check_PROGRAMS = \
bad_pointers_t bad_databases_t bad_data_size_t bad_epoch_t bad_indent_t \
bad_search_tree_t \
basic_lookup_t data_entry_list_t \
data-pool-t data_types_t double_close_t dump_t gai_error_t get_value_t \
data-pool-t data_types_t double_close_t dump_t empty_container_metadata_t \
gai_error_t get_value_t \
get_value_pointer_bug_t \
ipv4_start_cache_t ipv6_lookup_in_ipv4_t max_depth_t metadata_t \
metadata_pointers_t no_map_get_value_t overflow_bounds_t read_node_t \
Expand Down
42 changes: 42 additions & 0 deletions t/empty_container_metadata_t.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#include "maxminddb_test_helper.h"

static void test_db_opens_and_lookup_succeeds(const char *filename,
const char *open_msg) {
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, open_msg);

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_lookup_succeeds(
"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_lookup_succeeds(
"libmaxminddb-empty-array-last-in-metadata.mmdb",
"opened MMDB with empty array at end of metadata");
}

int main(void) {
plan(NO_PLAN);
test_empty_map_last_in_metadata();
test_empty_array_last_in_metadata();
done_testing();
}
Loading