“Misaligned address error” 是什么意思?

8

首先,非常抱歉这里有些具体。我通常会尽量将我的Stack Overflow问题简化为只包含相关内容的“A类”问题,但是我不确定这里的问题来源在哪里。

我有一个矩阵类模板,看起来像这样(仅显示我认为与问题相关的部分):

template <std::size_t R, std::size_t C>
class Matrix
{
private:
    //const int rows, cols;
    std::array<std::array<float,C>,R> m;
public:
    inline std::array<float,C>& operator[](const int i)
    {
        return m[i];
    }

    const std::array<float,C> operator[](const int i) const
    {
        return m[i];
    }

    template<std::size_t N>
    Matrix<R,N> operator *(const Matrix<C,N> a) const
    {
        Matrix<R,N> result = Matrix<R,N>();
        // irrelevant calculation
        return result;
    }
    // ... other very similar stuff, I'm not sure that it's relevant
}

template <std::size_t S>
Matrix<S,S> identity()
{
    Matrix<S,S> matrix = Matrix<S,S>();

    for(std::size_t x = 0; x < S; x++)
    {
        for(std::size_t y = 0; y < S; y++)
        {
            if (x == y)
            {
                matrix[x][y] = 1.f;
            }
        }
    }

    return matrix;
}

我对整个类进行了单元测试,乘法和单位工厂似乎都正常工作。然而,当我在这个方法中使用它时,它被大量调用(我认为如果你曾经编写过渲染器,你就知道我在尝试做什么):

Vec3i Renderer::world_to_screen_space(Vec3f v)
{
    Matrix<4,1> vm = v2m(v);
    Matrix<4,4> projection = identity<4>(); // If I change this to Matrix<4,4>(), the error doesn't happen
    projection[3][2] = -1.f;
    vm = projection * vm;
    Vec3f r = m2v(vm);
    return Vec3i(
            (r.x + 1.) * (width / 2.),
            (r.y + 1.) * (height / 2.),
            r.z
        );
}

经过一段时间和随机调用该方法后,我得到了这个结果:

Job 1, 'and ./bin/main' terminated by signal SIGBUS (Misaligned address error)

然而,如果我将行identity<4>()更改为Matrix<4,4>(),错误就不会发生。由于我是C++的新手,所以一定是做了什么非常愚蠢的事情。
那么,(1)这个错误意味着什么,(2)我是如何自己给自己惹麻烦的?
更新:当然,在LLDB调试器中无法重现此错误。
更新2:在通过Valgrind运行程序后,这是我得到的结果:
==66525== Invalid read of size 4
==66525==    at 0x1000148D5: Renderer::draw_triangle(Vec3<float>, Vec3<float>, Vec3<float>, Vec2<int>, Vec2<int>, Vec2<int>, Model, float) (in ./bin/main)

draw_triangle 是调用 world_to_screen_space 并使用其结果的方法。

更新3:我发现了问题的源头,与这段代码无关,而且也是相当明显的。真的不确定现在该怎么做这个问题。


6
"Misaligned address" 通常意味着您拥有一款CPU,该CPU对某些数据类型需要特定的对齐方式(例如,32位整数必须位于32位对齐的地址上,如0x1000或0x1004),而您的代码试图违反该要求(尝试从地址0x1001读取32位整数)。您可能在未展示的代码中使用了某种类型转换或其他形式的类型转换或不良指针算术... 或者可能存在损坏的指针... 或者还有其他几种可能性的解释... - twalberg
除非这里涉及到多个线程,否则我猜测你的std::array没有以满足处理器的方式对其内容进行对齐。如果有多个线程,我会认为是竞争条件。 - Collin Dauphinee
@CollinDauphinee 只有一个线程。这是否意味着 std::array 出现了问题?它怎么可能会出现问题? - Max Yankov
这是完整的Valgrind消息吗?我本来希望看到数据地址和代码地址。 - Ben Voigt
1
@golergka:更短、更简单的代码同样更容易正确。 - Ben Voigt
显示剩余8条评论
1个回答

5

没有检查对齐的处理器(如@twalberg所说),无法运行和验证代码。但我可以说:在C++或其他库中,混淆一种异常类型和另一种异常类型是常见的错误。

我的猜测 - 很抱歉我不能提供更多信息 - 是您正在创建会丢失的分配,使用可用的内存,然后溢出内存空间。当您超过可用内存时抛出的非常罕见的异常可能是意外的,并作为不对齐错误返回。尝试在运行时检查内存使用情况,以确定是否存在这种情况。

编辑:

我的猜测是错误的,valgrind输出显示Misaligned地址错误是正确的。进行这样的操作是一个好主意。明显的迹象表明,在您的代码之下存在错误,因此我的最初想法几乎肯定是正确的:存在错误,但不在您的代码中,而是被掩盖了。

请注意,似乎identity()构造函数和Matrix<,>构造函数之间存在差异,前者沿对角线初始化(缓慢:最好消除内部循环),而后者则不是。这可能会影响v2m和m2v的行为。


我发现了问题,结果发现它与我发布的代码无关,而是一个非常明显的问题。根据此处建议,我应该删除这个问题,但是这里有很多很好的讨论。不太确定该怎么处理它;不能接受这个答案,因为从技术上讲它是不正确的(它不是问题所在),尽管你帮了我大忙。 - Max Yankov
@golergka 你可以创建一个答案并接受它。这是一种理想的、标准的行为。 - edmz
@black 但是我的个人答案(1)对其他人没有用处,(2)会掩盖这个非常有用的答案,对任何人都很有帮助。 - Max Yankov
1
@golergka 我不能强迫你,但请注意这是 Stack Exchange 应该在这种情况下的工作方式。请阅读。你仍然可以在你的答案中指出你的笔记。 - edmz
1
@black 感谢这次讨论,我想我会在今天晚些时候写一篇关于这个问题的文章。 - Max Yankov
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接