我的 CS50 模糊滤镜上的 UndefinedBehaviorSanitizer

UndefinedBehaviorSanitizer on my CS50 Blur Filter

我似乎无法弄清楚为什么这个错误不断发生。我对编码还很陌生,这个程序应该使用框模糊来模糊图像,但是当我尝试执行该程序时出现错误。我知道这可能不是最有效的解决方案,但我将不胜感激有关如何让它工作的任何提示!

void blur(int height, int width, RGBTRIPLE image[height][width])
{
    RGBTRIPLE old[height][width];

    for(int i = 0; i < height; i++)
    {
        for(int j = 0; j < width; j++)
        {
            old[i][j] = image[i][j];
        }
    } 
    for(int i = 0; i < height; i++)
    {
        for(int j = 0; j < width; j++)
        {
            //top left corner
            if(j == 0 && i == 0)
            {
                image[i][j].rgbtRed = round( (old[i][j].rgbtRed + old[i][j+1].rgbtRed + old[i+1][j].rgbtRed + old[i+1][j+1].rgbtRed) /4);
                image[i][j].rgbtGreen = round( (old[i][j].rgbtGreen + old[i][j+1].rgbtGreen + old[i+1][j].rgbtGreen + old[i+1][j+1].rgbtGreen) /4);
                image[i][j].rgbtBlue = round( (old[i][j].rgbtBlue + old[i][j+1].rgbtBlue + old[i+1][j].rgbtBlue + old[i+1][j+1].rgbtBlue) /4);
            } 
            //top right corner
            else if(j == width && i == 0)
            {
                image[i][j].rgbtRed = round( (old[i][j].rgbtRed + old[i][j-1].rgbtRed + old[i+1][j].rgbtRed + old[i+1][j-1].rgbtRed) /4);
                image[i][j].rgbtGreen = round( (old[i][j].rgbtGreen + old[i][j-1].rgbtGreen + old[i+1][j].rgbtGreen + old[i+1][j-1].rgbtGreen) /4);
                image[i][j].rgbtBlue = round( (old[i][j].rgbtBlue + old[i][j-1].rgbtBlue + old[i+1][j].rgbtBlue + old[i+1][j-1].rgbtBlue) /4);
            } 
            //bottom left corner
            else if(j == 0 && i == height - 1)
            {
                image[i][j].rgbtRed = round( (old[i][j].rgbtRed + old[i][j+1].rgbtRed + old[i-1][j].rgbtRed + old[i-1][j+1].rgbtRed) /4);
                image[i][j].rgbtGreen = round( (old[i][j].rgbtGreen + old[i][j+1].rgbtGreen + old[i-1][j].rgbtGreen + old[i-1][j+1].rgbtGreen) /4);
                image[i][j].rgbtBlue = round( (old[i][j].rgbtBlue + old[i][j+1].rgbtBlue + old[i-1][j].rgbtBlue + old[i-1][j+1].rgbtBlue) /4);
            } 
            //bottom right corner
            else if(j == width && i == height - 1)
            {
                image[i][j].rgbtRed = round( (old[i][j].rgbtRed + old[i][j-1].rgbtRed + old[i-1][j].rgbtRed + old[i-1][j-1].rgbtRed) /4);
                image[i][j].rgbtGreen = round( (old[i][j].rgbtGreen + old[i][j-1].rgbtGreen + old[i-1][j].rgbtGreen + old[i-1][j-1].rgbtGreen) /4);
                image[i][j].rgbtBlue = round( (old[i][j].rgbtBlue + old[i][j-1].rgbtBlue + old[i-1][j].rgbtBlue + old[i-1][j-1].rgbtBlue) /4);
            } 
            //first row
            else if(i == 0 && j > 0 && j < width - 1)
            {
                image[i][j].rgbtRed = round( (old[i][j].rgbtRed + old[i][j+1].rgbtRed + old[i+1][j].rgbtRed + old[i+1][j+1].rgbtRed + old[i][j-1].rgbtRed + old[i+1][j-1].rgbtRed) /6);
                image[i][j].rgbtGreen = round( (old[i][j].rgbtGreen + old[i][j+1].rgbtGreen + old[i+1][j].rgbtGreen + old[i+1][j+1].rgbtGreen + old[i][j-1].rgbtGreen + old[i+1][j-1].rgbtGreen) /6);
                image[i][j].rgbtBlue = round( (old[i][j].rgbtBlue + old[i][j+1].rgbtBlue + old[i+1][j].rgbtBlue + old[i+1][j+1].rgbtBlue + old[i][j-1].rgbtBlue + old[i+1][j-1].rgbtBlue) /6);
            }
            //last row
            else if(i == height && j > 0 && j < width - 1)
            {
                image[i][j].rgbtRed = round( (old[i][j].rgbtRed + old[i][j+1].rgbtRed + old[i-1][j].rgbtRed + old[i-1][j+1].rgbtRed + old[i][j-1].rgbtRed + old[i-1][j-1].rgbtRed) /6);
                image[i][j].rgbtGreen = round( (old[i][j].rgbtGreen + old[i][j+1].rgbtGreen + old[i-1][j].rgbtGreen + old[i-1][j+1].rgbtGreen + old[i][j-1].rgbtGreen + old[i-1][j-1].rgbtGreen) /6);
                image[i][j].rgbtBlue = round( (old[i][j].rgbtBlue + old[i][j+1].rgbtBlue + old[i-1][j].rgbtBlue + old[i-1][j+1].rgbtBlue + old[i][j-1].rgbtBlue + old[i-1][j-1].rgbtBlue) /6);
            }
            //first column 
            else if(j == 0 && i > 0 && i < height - 1)
            {
                image[i][j].rgbtRed = round( (old[i][j].rgbtRed + old[i][j+1].rgbtRed + old[i+1][j].rgbtRed + old[i+1][j+1].rgbtRed + old[i-1][j].rgbtRed + old[i-1][j+1].rgbtRed) /6);
                image[i][j].rgbtGreen = round( (old[i][j].rgbtGreen + old[i][j+1].rgbtGreen + old[i+1][j].rgbtGreen + old[i+1][j+1].rgbtGreen + old[i-1][j].rgbtGreen + old[i-1][j+1].rgbtGreen) /6);
                image[i][j].rgbtBlue = round( (old[i][j].rgbtBlue + old[i][j+1].rgbtBlue + old[i+1][j].rgbtBlue + old[i+1][j+1].rgbtBlue + old[i-1][j].rgbtBlue + old[i-1][j+1].rgbtBlue) /6);
            }
            //last column
            else if(j == width && i > 0 && i < height - 1)
            {
                image[i][j].rgbtRed = round( (old[i][j].rgbtRed + old[i][j-1].rgbtRed + old[i+1][j].rgbtRed + old[i+1][j-1].rgbtRed + old[i-1][j].rgbtRed + old[i-1][j-1].rgbtRed) /6);
                image[i][j].rgbtGreen = round( (old[i][j].rgbtGreen + old[i][j-1].rgbtGreen + old[i+1][j].rgbtGreen + old[i+1][j-1].rgbtGreen + old[i-1][j].rgbtGreen + old[i-1][j-1].rgbtGreen) /6);
                image[i][j].rgbtBlue = round( (old[i][j].rgbtBlue + old[i][j-1].rgbtBlue + old[i+1][j].rgbtBlue + old[i+1][j-1].rgbtBlue + old[i-1][j].rgbtBlue + old[i-1][j-1].rgbtBlue) /6);
            }
            else if(i < height - 1 && j < width - 1)
            {
                image[i][j].rgbtRed = round( (old[i][j].rgbtRed + old[i][j+1].rgbtRed + old[i+1][j].rgbtRed + old[i+1][j+1].rgbtRed + old[i][j-1].rgbtRed + old[i+1][j-1].rgbtRed + old[i-1][j].rgbtRed + old[i-1][j-1].rgbtRed + old[j-1][i+1].rgbtRed) /9);
                image[i][j].rgbtGreen = round( (old[i][j].rgbtGreen + old[i][j+1].rgbtGreen + old[i+1][j].rgbtGreen + old[i+1][j+1].rgbtGreen + old[i][j-1].rgbtGreen + old[i+1][j-1].rgbtGreen + old[i-1][j].rgbtGreen + old[i-1][j-1].rgbtGreen + old[j-1][i+1].rgbtGreen) /9);
                image[i][j].rgbtBlue = round( (old[i][j].rgbtBlue + old[i][j+1].rgbtBlue + old[i+1][j].rgbtBlue + old[i+1][j+1].rgbtBlue + old[i][j-1].rgbtBlue + old[i+1][j-1].rgbtBlue + old[i-1][j].rgbtBlue + old[i-1][j-1].rgbtBlue + old[j-1][i+1].rgbtBlue) /9);
            }
        }
    }
}
UndefinedBehaviorSanitizer:DEADLYSIGNAL
==9889==ERROR: UndefinedBehaviorSanitizer: SEGV on unknown address 0x7fff298bd0b8 (pc 0x000000442a96 bp 0x7fff298bc2b0 sp 0x7fff298071c0 T9889)
==9889==The signal is caused by a READ memory access.
    #0 0x442a95  (/home/ubuntu/pset4/filter/filter+0x442a95)
    #1 0x4232f1  (/home/ubuntu/pset4/filter/filter+0x4232f1)
    #2 0x7f302ce5db96  (/lib/x86_64-linux-gnu/libc.so.6+0x21b96)
    #3 0x402e19  (/home/ubuntu/pset4/filter/filter+0x402e19)

UndefinedBehaviorSanitizer can not provide additional info.
==9889==ABORTING

当您尝试对如此多的边缘情况进行硬编码时(字面意思是呵呵),出现问题是可以预料的。为什么不尝试矩阵遍历呢?即构造一个假想矩阵,以当前像素([i][j])为中心,遍历该矩阵的所有有效像素并相加。简单高效。

// Blur image
void blur(int height, int width, RGBTRIPLE image[height][width])
{

    RGBTRIPLE old[height][width];
    for (int i = 0; i < height; i++)
    {
        // Copy the original image over to a temporary variable, row by row
        memcpy(old[i], image[i], sizeof(RGBTRIPLE) * width);
    }
    // Iterate through rows
    for (int i = 0; i < height; i++)
    {
        // Iterate through columns
        for (int j = 0, red, green, blue, count; j < width; j++)
        {
            // Reset the variables
            red = blue = green = count = 0;
            // Move row-wise in the imaginary matrix (centered around [i][j])
            for (int r = i - 1; r <= i + 1; r++)
            {
                // Move column-wise in the imaginary matrix (centered around [i][j])
                for (int c = j - 1; c <= j + 1; c++)
                {
                    // Check for invalid pixels
                    if (r < 0 || r > height - 1)
                    {
                        // Invalid row, no need to continue, move on to next row
                        break;
                    }
                    if (c > -1 && c < width)
                    {
                        // Valid pixel
                        count++;
                        // Sum up every pixel color
                        red += old[r][c].rgbtRed;
                        green += old[r][c].rgbtGreen;
                        blue += old[r][c].rgbtBlue;
                    }
                }
            }
            // Calculate the average and assign
            image[i][j].rgbtRed = round((float)red / count);
            image[i][j].rgbtGreen = round((float)green / count);
            image[i][j].rgbtBlue = round((float)blue / count);
        }
    }
    return;
}

这与您想要实现的相同,除了围绕每个像素构造一个虚构矩阵,并检查内部索引 所述矩阵 - 我们使这个问题简单得多。

“我似乎无法弄清楚为什么这个错误不断发生。”
(关于异常信号:==9889==The signal is caused by a READ memory access.

虽然我同意其他答案中提供的建议,但它没有解决您提出的核心问题,这很可能是由您代码中某处未定义的行为引起的。

注意:错误陈述:signal is caused by a READ memory access.undefined behavior, (UB) for which my favorite definition 的症状与您所看到的相符。具体来说,您的代码在某些时候试图写入不属于它的内存。如果正在写入的无主内存恰好不属于任何其他进程,那么您的程序甚至可能不会抛出异常。但是在你的情况下,很可能你的进程不拥有的内存 由另一个进程拥有,导致 OS 抱怨并发出你正在侵入的异常信号另一个的属性(内存位置)。

有趣的是,您 post 编辑的代码没有明显迹象表明赋值试图访问不属于自己的内存。为所有赋值绑定嵌套循环的条件:

   for(int i = 0; i < height; i++)
    {
        for(int j = 0; j < width; j++)

显然不允许 ij 索引超出 image 数组的边界。 以及随后的语句如:

else if(j == width && i == 0)

被 for 循环中的条件限制 运行 永远不允许 j == width,从而防止 可能 尝试编写 for image[i][j].rgbtRed 的例子(如果 j == width 会使数组的一个内存位置超出范围。)并且是异常的原因。

所以我建议可能是代码未posted导致异常发生。 (您从未回答 评论中的问题 错误发生的确切位置。)您还没有找到它。找到根本原因并将其消除是一个很好的举措。

或者,您可以 post 一个 minimal but complete, compilable example 从而更好地让访问此 post 的其他人帮助您找到它。

EDIT - 我 运行 你的代码只有一个 main() 函数(见下文)执行此操作,但在您post编辑 的代码片段中没有发现读取内存访问违规的证据。我坚信此时问题出在其他地方,也许在您没有包括的一段代码中:

   typedef struct {
        int rgbtRed;    
        int rgbtGreen;
        int rgbtBlue;
    }RGBTRIPLE;
    

    void blur(int height, int width, RGBTRIPLE image[height][width]);
    
    int main(void)
    {
        
        RGBTRIPLE image[2][3] = {{{12,13,14},{14,15,16},{15,16,17}},{{16,17,18},{17,18,19},{18,19,20}}};
        blur(2, 3, image);
        return 0;
    }

    

在场景中,例如j==width-1,对 old[i][j+1] 的访问将超出内部数组的末尾。尽管丹尼斯·里奇 (Dennis Ritchie) 设计的 C 语言允许超出内部数组边界但最终位于外部数组内的访问,但如果尝试进行此类访问,该标准允许实现陷入陷阱或行为异常。我怀疑 UndefinedbehaviorSanitizer 正在标记此类访问。