Repository: dotnet/runtime
File: src/tasks/AppleAppBuilder/Templates/runtime-coreclr.m (Objective-C)

Code before:

            cmd = (const struct load_command*)((const char*)cmd + cmd->cmdsize);
        }

        return image_size;
    }
}

bool get_native_code_data(const struct host_runtime_contract_native_code_context* context, struct host_runtime_contract_native_code_data* data)
{
    if (!context || !data || !context->assembly_path || !context->owner_composite_name)
        return false;

    // Look for the owner composite R2R image in the same directory as the assembly
    char r2r_path[PATH_MAX];
    const char *last_slash = strrchr(context->assembly_path, '/');
    size_t dir_len = last_slash ? (size_t)(last_slash - context->assembly_path) : 0;
    if (dir_len >= sizeof(r2r_path) - 1)
        return false;

    strncpy(r2r_path, context->assembly_path, dir_len);
    int written = snprintf(r2r_path + dir_len, sizeof(r2r_path) - dir_len, "/%s", context->owner_composite_name);
    if (written <= 0 || (size_t)written >= sizeof(r2r_path) - dir_len)
        return false;

    assert(loaded_native_code_handle_count < MAX_LOADED_NATIVE_CODE_COUNT);
    void* handle = dlopen(r2r_path, RTLD_LAZY | RTLD_LOCAL);
    if (handle == NULL)
        return false;

    loaded_native_code_handles[loaded_native_code_handle_count] = handle;
    loaded_native_code_handle_count++;

    void* r2r_header = dlsym(handle, "RTR_HEADER");
    if (r2r_header == NULL)
    {
        dlclose(handle);
        return false;
    }

    Dl_info info;
    if (dladdr(r2r_header, &info) == 0)
    {
        dlclose(handle);
        return false;
    }

    data->size = sizeof(struct host_runtime_contract_native_code_data);
    data->r2r_header_ptr = r2r_header;
    data->image_size = get_image_size(info.dli_fbase);
    data->image_base = info.dli_fbase;

Review comment (bug):
The `assert` is insufficient protection against buffer overflow. If `loaded_native_code_handle_count` equals or exceeds `MAX_LOADED_NATIVE_CODE_COUNT`, writing to the array will cause a buffer overflow. This check should be a runtime check that returns `false` instead of an assertion. Replace with:
```c
if (loaded_native_code_handle_count >= MAX_LOADED_NATIVE_CODE_COUNT)
    return false;
```
```suggestion
    if (loaded_native_code_handle_count >= MAX_LOADED_NATIVE_CODE_COUNT)
        return false;
```

Code after:

    // Look for the owner composite R2R image in the same directory as the assembly
    char r2r_path[PATH_MAX];
    const char *last_slash = strrchr(context->assembly_path, '/');
    size_t dir_len = last_slash ? (size_t)(last_slash - context->assembly_path) : 0;
    if (dir_len >= sizeof(r2r_path) - 1)
        return false;

    strncpy(r2r_path, context->assembly_path, dir_len);
    int written = snprintf(r2r_path + dir_len, sizeof(r2r_path) - dir_len, "/%s", context->owner_composite_name);
    if (written <= 0 || (size_t)written >= sizeof(r2r_path) - dir_len)
        return false;

    void* handle = dlopen(r2r_path, RTLD_LAZY | RTLD_LOCAL);
    if (handle == NULL)
        return false;

    void* r2r_header = dlsym(handle, "RTR_HEADER");
    if (r2r_header == NULL)
    {
        dlclose(handle);
        return false;
    }

    Dl_info info;
    if (dladdr(r2r_header, &info) == 0)
    {
        dlclose(handle);
        return false;
    }

    // The base address points to the Mach header
    void* base_address = info.dli_fbase;
    const struct mach_header_64* header = (const struct mach_header_64*)base_address;

    data->size = sizeof(struct host_runtime_contract_native_code_data);
    data->r2r_header_ptr = r2r_header;
    data->image_size = get_image_size(header);
    data->image_base = base_address;
    return true;
}

void
mono_ios_runtime_init (void)
{
#if INVARIANT_GLOBALIZATION
    setenv ("DOTNET_SYSTEM_GLOBALIZATION_INVARIANT", "1", TRUE);
#endif

#if HYBRID_GLOBALIZATION
    setenv ("DOTNET_SYSTEM_GLOBALIZATION_HYBRID", "1", TRUE);