Skip to content

Commit 5e26afb

Browse files
committed
Fix invalid memory read for table with many flag/pair ids
1 parent 31c352a commit 5e26afb

File tree

5 files changed

+64
-5
lines changed

5 files changed

+64
-5
lines changed

distr/flecs.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36771,7 +36771,7 @@ void flecs_table_init(
3677136771
* we're adding the next set of records */
3677236772
if (first_role != -1 || first_pair != -1) {
3677336773
int32_t start = first_role;
36774-
if (first_pair != -1 && (start != -1 || first_pair < start)) {
36774+
if (first_pair != -1 && (start == -1 || first_pair < start)) {
3677536775
start = first_pair;
3677636776
}
3677736777

@@ -36786,6 +36786,10 @@ void flecs_table_init(
3678636786
ecs_vec_set_min_size_t(a, records, ecs_table_record_t, record_count);
3678736787
}
3678836788

36789+
/* Get records size now so we can check that array did not resize */
36790+
int32_t records_size = ecs_vec_size(records);
36791+
(void)records_size;
36792+
3678936793
/* Add records for ids with roles (used by cleanup logic) */
3679036794
if (first_role != -1) {
3679136795
for (dst_i = first_role; dst_i < dst_count; dst_i ++) {
@@ -36902,6 +36906,11 @@ void flecs_table_init(
3690236906
/* If this is a target wildcard record it has already been
3690336907
* registered, but the record is now at a different location in
3690436908
* memory. Patch up the linked list with the new address */
36909+
36910+
/* Ensure that record array hasn't been reallocated */
36911+
ecs_assert(records_size == ecs_vec_size(records),
36912+
ECS_INTERNAL_ERROR, NULL);
36913+
3690536914
ecs_table_cache_replace(&idr->cache, table, &tr->hdr);
3690636915
} else {
3690736916
/* Other records are not registered yet */

src/storage/table.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,7 @@ void flecs_table_init(
447447
* we're adding the next set of records */
448448
if (first_role != -1 || first_pair != -1) {
449449
int32_t start = first_role;
450-
if (first_pair != -1 && (start != -1 || first_pair < start)) {
450+
if (first_pair != -1 && (start == -1 || first_pair < start)) {
451451
start = first_pair;
452452
}
453453

@@ -462,6 +462,10 @@ void flecs_table_init(
462462
ecs_vec_set_min_size_t(a, records, ecs_table_record_t, record_count);
463463
}
464464

465+
/* Get records size now so we can check that array did not resize */
466+
int32_t records_size = ecs_vec_size(records);
467+
(void)records_size;
468+
465469
/* Add records for ids with roles (used by cleanup logic) */
466470
if (first_role != -1) {
467471
for (dst_i = first_role; dst_i < dst_count; dst_i ++) {
@@ -578,6 +582,11 @@ void flecs_table_init(
578582
/* If this is a target wildcard record it has already been
579583
* registered, but the record is now at a different location in
580584
* memory. Patch up the linked list with the new address */
585+
586+
/* Ensure that record array hasn't been reallocated */
587+
ecs_assert(records_size == ecs_vec_size(records),
588+
ECS_INTERNAL_ERROR, NULL);
589+
581590
ecs_table_cache_replace(&idr->cache, table, &tr->hdr);
582591
} else {
583592
/* Other records are not registered yet */

test/core/project.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2410,7 +2410,8 @@
24102410
"clear_table_check_size",
24112411
"clear_table_twice_check_size",
24122412
"clear_table_on_remove_hooks",
2413-
"clear_table_on_remove_observer"
2413+
"clear_table_on_remove_observer",
2414+
"65_records_w_tgt"
24142415
]
24152416
}, {
24162417
"id": "Poly",

test/core/src/Table.c

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -765,7 +765,7 @@ void Observer(ecs_iter_t *it) {
765765
}
766766

767767
void Table_clear_table_on_remove_observer(void) {
768-
ecs_world_t *world = ecs_mini();
768+
ecs_world_t *world = ecs_mini();
769769

770770
ECS_COMPONENT(world, Position);
771771

@@ -793,3 +793,38 @@ void Table_clear_table_on_remove_observer(void) {
793793

794794
ecs_fini(world);
795795
}
796+
797+
void Table_65_records_w_tgt(void) {
798+
ecs_world_t *world = ecs_mini();
799+
800+
ECS_TAG(world, RelA);
801+
ECS_TAG(world, TgtA);
802+
803+
ECS_TAG(world, RelB);
804+
ECS_TAG(world, TgtB);
805+
806+
ecs_id_t *ids = ecs_os_malloc_n(ecs_id_t, 39);
807+
int32_t i;
808+
809+
for (i = 0; i < 19; i ++) {
810+
ids[i] = ecs_new(world);
811+
}
812+
813+
for (; i < 37; i ++) {
814+
ids[i] = ECS_AUTO_OVERRIDE | ecs_new(world);
815+
}
816+
817+
ids[i ++] = ecs_pair(RelA, TgtA);
818+
ids[i ++] = ecs_pair(RelB, TgtB);
819+
820+
ecs_table_t *table = ecs_table_find(world, ids, i);
821+
test_assert(table != NULL);
822+
823+
for (i = 0; i < 39; i ++) {
824+
test_assert(ecs_table_has_id(world, table, ids[i]));
825+
}
826+
827+
ecs_os_free(ids);
828+
829+
ecs_fini(world);
830+
}

test/core/src/main.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2324,6 +2324,7 @@ void Table_clear_table_check_size(void);
23242324
void Table_clear_table_twice_check_size(void);
23252325
void Table_clear_table_on_remove_hooks(void);
23262326
void Table_clear_table_on_remove_observer(void);
2327+
void Table_65_records_w_tgt(void);
23272328

23282329
// Testsuite 'Poly'
23292330
void Poly_on_set_poly_observer(void);
@@ -11373,6 +11374,10 @@ bake_test_case Table_testcases[] = {
1137311374
{
1137411375
"clear_table_on_remove_observer",
1137511376
Table_clear_table_on_remove_observer
11377+
},
11378+
{
11379+
"65_records_w_tgt",
11380+
Table_65_records_w_tgt
1137611381
}
1137711382
};
1137811383

@@ -11821,7 +11826,7 @@ static bake_test_suite suites[] = {
1182111826
"Table",
1182211827
NULL,
1182311828
NULL,
11824-
30,
11829+
31,
1182511830
Table_testcases
1182611831
},
1182711832
{

0 commit comments

Comments
 (0)