SanderMertens / flecs

A fast entity component system (ECS) for C & C++

Home Page:https://www.flecs.dev

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Crash On flecs_defer_end

Esp9527 opened this issue · comments

Describe the bug

flecs 3.2.9

To Reproduce
Crash On flecs source code ( event is EcsCmdEvent )

`

 bool flecs_defer_end(
    ecs_world_t *world,
    ecs_stage_t *stage)
{

    // event is EcsCmdEvent
    if (cmd->is._1.value) {
        // Crash Here
        flecs_stack_free(cmd->is._1.value, cmd->is._1.size);
    }
}

`

Because flecs_cmd_new don't set cmd->is._1.size (0 or 1) in flecs_enqueue?
`

Here is code

void flecs_enqueue(
    ecs_world_t *world,
    ecs_stage_t *stage,
    ecs_event_desc_t *desc)
{
    ecs_cmd_t *cmd = flecs_cmd_new(stage);
    cmd->kind = EcsCmdEvent;
    cmd->entity = desc->entity;

    ecs_stack_t *stack = &stage->cmd->stack;
    ecs_event_desc_t *desc_cmd = flecs_stack_alloc_t(stack, ecs_event_desc_t);
    ecs_os_memcpy_t(desc_cmd, desc, ecs_event_desc_t);

    if (desc->ids && desc->ids->count != 0) {
        ecs_type_t *type_cmd = flecs_stack_alloc_t(stack, ecs_type_t);
        int32_t id_count = desc->ids->count;
        type_cmd->count = id_count;
        type_cmd->array = flecs_stack_alloc_n(stack, ecs_id_t, id_count);
        ecs_os_memcpy_n(type_cmd->array, desc->ids->array, ecs_id_t, id_count);
        desc_cmd->ids = type_cmd;
    } else {
        desc_cmd->ids = NULL;
    }

    cmd->is._1.value = desc_cmd;

    if (desc->param || desc->const_param) {
        ecs_assert(!(desc->const_param && desc->param), ECS_INVALID_PARAMETER, 
            "cannot set param and const_param at the same time");

        const ecs_type_info_t *ti = ecs_get_type_info(world, desc->event);
        ecs_assert(ti != NULL, ECS_INVALID_PARAMETER, 
            "can only enqueue events with data for events that are components");

        void *param_cmd = flecs_stack_alloc(stack, ti->size, ti->alignment);
        ecs_assert(param_cmd != NULL, ECS_INTERNAL_ERROR, NULL);
        if (desc->param) {
            if (ti->hooks.move_ctor) {
                ti->hooks.move_ctor(param_cmd, desc->param, 1, ti);
            } else {
                ecs_os_memcpy(param_cmd, desc->param, ti->size);
            }
        } else {
            if (ti->hooks.copy_ctor) {
                ti->hooks.copy_ctor(param_cmd, desc->const_param, 1, ti);
            } else {
                ecs_os_memcpy(param_cmd, desc->const_param, ti->size);
            }
        }

        desc_cmd->param = param_cmd;
        desc_cmd->const_param = NULL;
    }
}

`

Expected behavior
A clear and concise description of what you expected to happen.

Additional context

I'm not very familiar with the underlying mechanism, is Here missing initialization?
`

static
ecs_cmd_t* flecs_cmd_new(
    ecs_stage_t *stage)
{
    ecs_cmd_t *cmd = ecs_vec_append_t(&stage->allocator, &stage->cmd->queue, 
        ecs_cmd_t);
    cmd->is._1.value = NULL;
    cmd->next_for_entity = 0;
    cmd->entry = NULL;
     // add set zero here ?
    cmd->id = 0;
    cmd->is._1.size = 0;
    return cmd;
}

`

Can you provide a reproducer for this issue?

Both size and value should be initialized (size to 0 by flecs_cmd_new, value by flecs_enqueue), so I think something else might be causing this. I also tried to initialize the result of ecs_vec_append_t with random data, which also didn't reproduce the issue.

Yesterday's description of the crash was not very clear
`

  void flecs_stack_free(
      void *ptr,
      ecs_size_t size)
  {
       // crash when cmd->is._1.size > ECS_STACK_PAGE_SIZE
      if (size > ECS_STACK_PAGE_SIZE) {
          // but ptr is stack ptr when EcsCmdEvent 
          ecs_os_free(ptr);
      }
  }

`
I'll try to reproduce this problem

Here are code will crash on my pc (Win11), flecs v3.2.9

`

  #include <flecs.h>
  #include <iostream>
  
  static const uint64_t PLAYER_SIZE = 8888;
  static const uint64_t EFFECT_SIZE = 10;
  
  static const uint64_t PLAYER_COUNT = 20;
  static const uint64_t EFFECT_COUNT = 20;
  
  struct Player{
      char data[PLAYER_SIZE] = {};
  };
  
  struct Effect {
      char data[EFFECT_SIZE] = {};
  };
  
  int main() {
  
      flecs::world world;
  
      world.component<Player>();
      world.component<Effect>();
  
      world.system<Player>()
          .each([](flecs::entity p, Player){
              Effect effect = {};
              for(int i = 0; i< EFFECT_COUNT;++i) {
                  p.world().event<Effect>()
                          .ctx(effect)
                          .id<Player>()
                          .entity(p)
                          .enqueue();
              }
          });
  
      world.observer<>()
          .event<Effect>()
          .term<Player>()
          .each([](flecs::entity){
              std::cout << "do effect" << std::endl;
          });
  
      world.defer_begin();
      for(int i = 0; i< PLAYER_COUNT; ++i) {
          auto player = world.entity();
          player.set<Player>({});
      }
      world.defer_end();
  
  //    ecs_log_set_level(3);
      world.app().target_fps(20).run();
      return 0;
  }

`
ps : if change PLAYER_COUNT = 1, EFFECT_COUNT =1, will crash on malloc function or free function (in random). maybe same reason cause whem memry is bad

That reproduced! Thanks :)