Skip to content

Bug: AssimpLibraryNameContainer.Linux loads libassimp.so.5 but struct definitions match Assimp 6.x ABI #2556

Description

@jhm-ciberman

Summary

On Windows, Assimp.GetApi() loads Assimp64.dll which is Assimp 6.x. On Linux and macOS, it loads libassimp.so.5 / libassimp.5.dylib which is Assimp 5.x. The .NET struct definitions match the 6.x ABI, so everything works on Windows but silently produces corrupt data on Linux/macOS.

The native NuGet package actually ships both versions (libassimp.so.5 and libassimp.so.6) in runtimes/linux-x64/native/, but AssimpLibraryNameContainer only requests the v5 binary:

public override string[] Linux => new[] { "libassimp.so.5" };   // loads Assimp 5.x
public override string[] MacOS => new[] { "libassimp.5.dylib" }; // loads Assimp 5.x

The concrete mismatch: QuatKey includes the MInterpolation field added in Assimp 6.x, making it 32 bytes. The native v5 aiQuatKey is only 24 bytes (no mInterpolation). Array indexing past element 0 reads at the wrong offset. (VectorKey also has the extra field but its stride happens to be 24 bytes in both versions due to alignment padding, so position/scale keys are unaffected.)

Impact

Any code that accesses animation keyframe arrays (MRotationKeys[i], MPositionKeys[i], MScalingKeys[i]) with i > 0 reads data at the wrong offset on Linux. Element 0 happens to work because both versions start at the same base address. Every subsequent element is shifted by 8 bytes (32 - 24), producing garbage quaternion/vector data.

This makes skeletal animation completely broken on Linux while working correctly on Windows (where Assimp64.dll is the v6 binary).

Reproduction

var assimp = Assimp.GetApi();
Scene* scene = assimp.ImportFile("model_with_animation.dae", 0);
Animation* anim = scene->MAnimations[0];
NodeAnim* ch = anim->MChannels[0];

// Element 0 is correct
Console.WriteLine(ch->MRotationKeys[0].MValue); // OK

// Element 1 reads at offset 32, but native data is at offset 24
Console.WriteLine(ch->MRotationKeys[1].MValue); // Garbage on Linux, correct on Windows

Workaround

Bypass Assimp.GetApi() and pass the correct library name: (Tested on WSL)

public static Assimp GetApi()
{
    if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
    {
        return new Assimp(Assimp.CreateDefaultContext(
            new[] { "libassimp.so.6", "libassimp.so.5", "libassimp" }));
    }
    return Assimp.GetApi();
}

Suggested fix

Update AssimpLibraryNameContainer.cs to prefer libassimp.so.6:

public override string[] Linux => new[] { "libassimp.so.6", "libassimp.so.5" };
public override string[] MacOS => new[] { "libassimp.6.dylib", "libassimp.5.dylib" };
public override string[] Android => new[] { "libassimp.so.6", "libassimp.so.5" };

Environment

  • Silk.NET: 2.23.0 (latest 2.x)
  • Platform: Linux x64 (Ubuntu 24.04, WSL2)
  • .NET: 10.0
  • Native binaries in NuGet: both libassimp.so.5 and libassimp.so.6 are shipped, only .so.5 is loaded

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    Status
    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions