1

我正在调试一个用 D 编写的相当简单的程序,它似乎有随机机会接收到 SEGV 信号。经过进一步检查,我观察到使用不同的编译器和构建模式会产生不同的结果。

我的测试结果:

  • DMD 调试 = 99% 的时间都可以工作
  • DMD 释放 = 50/50
  • LDC 调试 = 50/50
  • 最不发达国家释放 = 50/50

因为默认编译器 (DMD) 中的二进制文件仅在我无法真正调试时崩溃,并且由于缺少调试符号,发布模式也无济于事。在调试模式下使用 LDC 构建二进制文件让我使用 gdb 和 valgrind 对其进行测试,以总结我收集到的内容。

来自valgrind的相关信息,

Invalid read of size 4 @ ctor in file video.d line 46

Access not within mapped region at address 0x0 @ ctor in file video.d line 

Gdb 没有给我更多的见解,3 个堆栈帧,其中只有第 0 个感兴趣,第 0 帧的回溯显示文件 video.d 第 46 行,这是一个中断语句,那么现在呢?

这是产生段错误的代码片段

module video;

import ffmpeg.libavformat.avformat;
import ffmpeg.libavcodec.avcodec; 
import ffmpeg.libavutil.avutil;

class Foo
{
    private
    {
        AVFormatContext* _format_ctx;
        AVStream* _stream_video;
        AVStream* _stream_audio;
    }

    ...

    public this(const(string) path)
    {
        import std.string : toStringz;

        _format_ctx = null;
        enforce(avformat_open_input(&_format_ctx, path.toStringz, null, null) == 0);
        scope (failure) avformat_close_input(&_format_ctx);

        enforce(avformat_find_stream_info(_format_ctx, null) == 0);
        debug av_dump_format(_format_ctx, 0, path.toStringz, 0);

        foreach (i; 0 .. _format_ctx.nb_streams)
        {
            AVStream* stream = _format_ctx.streams[i];

            if (stream == null)
                continue;

            enforce (stream.codecpar != null);

            switch (stream.codecpar.codec_type)
            {
                case AVMediaType.AVMEDIA_TYPE_VIDEO:
                    _stream_video = stream;
                    break;
                case AVMediaType.AVMEDIA_TYPE_AUDIO:
                    _stream_audio = stream;
                    break;
                default:
                    stream.discard = AVDiscard.AVDISCARD_ALL;
                    break; // Magic line 46
            }
        }
    }
}

// Might contain spelling errors, had to write it by hand.

那么有没有人知道是什么导致了这种行为,或者更准确地说是如何解决它?

4

2 回答 2

0

您没有遵守toStringz文档中的警告:

“重要提示:将 char* 传递给 C 函数时,C 函数出于任何原因保留它,请确保在 D 代码中保留对它的引用。否则,它可能会在垃圾回收周期中变得无效,并在 C 代码尝试使用它时导致严重的错误。”</p>

这可能不是您的问题的原因,但您使用的方式toStringz是有风险的。

于 2019-07-23T13:57:05.307 回答
0

尝试检查有效性_stream_audio

default:
    enforce( _stream_audio, new Exception( "_stream_audio is null" ))
        .discard = AVDiscard.AVDISCARD_ALL;
    break; // Magic line 46
于 2019-07-22T21:14:14.027 回答