意外的非空返回

发布于 2024-10-07 09:16:43 字数 3097 浏览 2 评论 0原文

我正在使用 TagLib(在 Windows 上,使用 MingW 构建)。我试图让 TagLib 识别 MP3 文件中没有 ID3v1 或 ID3v2 信息。根据 TagLib 文档, ID3v2Tag() 函数当文件中没有 ID3v2 信息时,MPEG 文件对象应返回 NULL 指针。

不幸的是,这并没有发生。我制作了一些在代码中使用的测试 MP3 文件(我已使这些文件可用):

  • blank.mp3 (download),根本没有 ID3v1 或 ID3v2 信息。我可以通过在文件二进制内容中对“TAG”和“ID3”进行纯文本搜索来确认这一点。
  • only_album_id3v2.mp3下载),有ID3v2信息(仅设置专辑)
  • only_album_id3v1.mp3 (download),有ID3v1信息(仅设置专辑)

这是我的代码。

#include <iostream>

#include <mpeg/mpegfile.h>
#include <mpeg/id3v2/id3v2tag.h>

using namespace std;

int main()
{
    cout << "Test." << endl;

    TagLib::MPEG::File a("tests/other/blank.mp3");
    TagLib::MPEG::File b("tests/id3v2/only_album_id3v2.mp3");
    TagLib::MPEG::File c("tests/id3v1/only_album_id3v1.mp3");


    TagLib::ID3v2::Tag * at = a.ID3v2Tag();
    TagLib::ID3v2::Tag * bt = b.ID3v2Tag();
    TagLib::ID3v2::Tag * ct = c.ID3v2Tag();

    cout << at->album() << endl;
    cout << bt->album() << endl;
    cout << ct->album() << endl;

    cout << "The program is done.";

    return 0;
}

由于 cout << 上出现 NULL 指针错误,运行该程序应该会中断。 at->album() << endl;,但运行得很好。另外,当我cout << ct << endl;,它返回一个内存地址。

这是输出:

测试。

测试专辑id3v2

程序已完成。

编辑: 这是一个新的测试。

#include <iostream>

#include <mpeg/mpegfile.h>
#include <mpeg/id3v2/id3v2tag.h>

using namespace std;

int main()
{
    cout << "Test." << endl;

    TagLib::MPEG::File a("tests/other/blank.mp3");
    TagLib::MPEG::File b("tests/id3v2/only_album_id3v2.mp3");
    TagLib::MPEG::File c("tests/id3v1/only_album_id3v1.mp3");


    TagLib::ID3v2::Tag * at = a.ID3v2Tag();
    TagLib::ID3v2::Tag * bt = b.ID3v2Tag();
    TagLib::ID3v2::Tag * ct = c.ID3v2Tag();

    if(at == NULL)
    {
        cout << "at is NULL.";
    }
    else
    {
        cout << "at is not NULL.";
    }
    cout << endl;

    if(bt == NULL)
    {
        cout << "bt is NULL.";
    }
    else
    {
        cout << "bt is not NULL.";
    }
    cout << endl;

    if(ct == NULL)
    {
        cout << "ct is NULL.";
    }
    else
    {
        cout << "ct is not NULL.";
    }
    cout << endl;

    cout << "The program is done.";

    return 0;
}

这是输出。

测试。
at 不为 NULL。
bt 不为 NULL。
ct 不为 NULL。
程序完成了。

I am playing with TagLib (on Windows, built with MingW). I am trying to get TagLib to recognize when there is no ID3v1 or ID3v2 information in an MP3 file. According to the TagLib documentation, the ID3v2Tag() function in an MPEG File object should return a NULL pointer when there is no ID3v2 information in the file.

Unfortunately, this is not occurring. I have some test MP3 files I have made that I use in my code (I have made the files available):

  • blank.mp3 (download), no ID3v1 or ID3v2 information at all. I can confirm this by doing a plain text search for "TAG" and "ID3" in the files binary content.
  • only_album_id3v2.mp3 (download), has ID3v2 information (only the album is set)
  • only_album_id3v1.mp3 (download), has ID3v1 information (only the album is set)

Here is my code.

#include <iostream>

#include <mpeg/mpegfile.h>
#include <mpeg/id3v2/id3v2tag.h>

using namespace std;

int main()
{
    cout << "Test." << endl;

    TagLib::MPEG::File a("tests/other/blank.mp3");
    TagLib::MPEG::File b("tests/id3v2/only_album_id3v2.mp3");
    TagLib::MPEG::File c("tests/id3v1/only_album_id3v1.mp3");


    TagLib::ID3v2::Tag * at = a.ID3v2Tag();
    TagLib::ID3v2::Tag * bt = b.ID3v2Tag();
    TagLib::ID3v2::Tag * ct = c.ID3v2Tag();

    cout << at->album() << endl;
    cout << bt->album() << endl;
    cout << ct->album() << endl;

    cout << "The program is done.";

    return 0;
}

Running this program should break, due to a NULL pointer error on cout << at->album() << endl;, but it runs just fine. Also, when I cout << ct << endl;, it returns a memory address.

Here is the output:

Test.

test album id3v2

The program is done.

EDIT:
Here is a new test.

#include <iostream>

#include <mpeg/mpegfile.h>
#include <mpeg/id3v2/id3v2tag.h>

using namespace std;

int main()
{
    cout << "Test." << endl;

    TagLib::MPEG::File a("tests/other/blank.mp3");
    TagLib::MPEG::File b("tests/id3v2/only_album_id3v2.mp3");
    TagLib::MPEG::File c("tests/id3v1/only_album_id3v1.mp3");


    TagLib::ID3v2::Tag * at = a.ID3v2Tag();
    TagLib::ID3v2::Tag * bt = b.ID3v2Tag();
    TagLib::ID3v2::Tag * ct = c.ID3v2Tag();

    if(at == NULL)
    {
        cout << "at is NULL.";
    }
    else
    {
        cout << "at is not NULL.";
    }
    cout << endl;

    if(bt == NULL)
    {
        cout << "bt is NULL.";
    }
    else
    {
        cout << "bt is not NULL.";
    }
    cout << endl;

    if(ct == NULL)
    {
        cout << "ct is NULL.";
    }
    else
    {
        cout << "ct is not NULL.";
    }
    cout << endl;

    cout << "The program is done.";

    return 0;
}

And here is the output.

Test.
at is not NULL.
bt is not NULL.
ct is not NULL.
The program is done.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

雪落纷纷 2024-10-14 09:16:43

我简单地检查了 TagLib 的代码。

我对此一无所知,也从未使用过它,但代码对我来说看起来有问题。原因如下 -

在 MPEG::File::read() 中,我们正在寻找标签 - d->ID3v2Location = findID3v2();。如果它不存在,则不会将其添加到标签向量中。这是检查 - if(d->ID3v2Location >= 0)

然而,在函数结束时,就在返回之前,我们有 -

// Make sure that we have our default tag types available.
ID3v2Tag(true);
ID3v1Tag(true);

现在,带有 true 参数的 Id3v2Tag(create) ,实际上调用了 return d->tag.access(ID3v2Index,创建);。 access() 函数是 -

template <class T> T *access(int index, bool create)
{
  if(!create || tag(index))
    return static_cast<T *>(tag(index));

  set(index, new T);
  return static_cast<T *>(tag(index));
}

因此,当 create 为 true 时,我们将创建一个全新的空标签并将其放入向量中(使用 set() 函数) 。

这意味着无论文件是否包含标签,它们都会添加到向量中。这不是记录的行为。看起来像一个错误。

我不知道为什么需要这两行 - 查看该文件的历史记录可能会暗示为什么添加它们,但我没有这样做。

不管怎样,我想强调的是我从未真正执行过这段代码。这是基于纯粹静态地仅读取非常小的部分,而没有意识到大规模问题。

我认为打开错误报告不会有什么坏处。

I examined TagLib's code briefly.

I know nothing about it and never used it, but the code looks buggy to me. Here's why -

In MPEG::File::read(), we are looking for a tag - d->ID3v2Location = findID3v2();. If it doesn't exist, it isn't added to the tags vector. This is the check - if(d->ID3v2Location >= 0).

However, at the end of the function, just before returning, we have -

// Make sure that we have our default tag types available.
ID3v2Tag(true);
ID3v1Tag(true);

Now, Id3v2Tag(create) with a true parameter, actually calls return d->tag.access(ID3v2Index, create);. The access() function is -

template <class T> T *access(int index, bool create)
{
  if(!create || tag(index))
    return static_cast<T *>(tag(index));

  set(index, new T);
  return static_cast<T *>(tag(index));
}

So when create is true, we are creating a brand new, empty tag and placing it in the vector (using the set() function).

This means that no matter whether the file contains the tags or not, they are added to the vector. This isn't the documented behavior. Looks like a bug.

I don't know why these two lines are needed there - looking at the history of this file might hint as to why they were added, but I didn't do that.

Anyway, I want to stress that I never actually executed this code. This is based on purely statically reading only very small parts, without being aware of large scale issues.

I think that opening a bug report can't hurt.

隱形的亼 2024-10-14 09:16:43

使用空指针并不一定会导致您看到的任何错误;这是未定义的行为。它可能看起来有效,或者可能会做一些非常非常奇怪的事情。

在这种情况下,编译器可能会生成对 TagLib::ID3v2::Tag::album 的调用,并将 this 指针设置为 null,但即使这样也不能保证。函数内部发生了什么是任何人的猜测。

如果函数可以返回 NULL,您应该显式检查它并执行不同的操作。

Using a null pointer doesn't necessarily result in any error you can see; it's undefined behavior. It might appear to work, or it might do something really really weird.

In this case the compiler is probably generating a call to TagLib::ID3v2::Tag::album with the this pointer set to null, but even this is not guaranteed. What happens inside the function is anyone's guess.

If the function can return NULL, you should be explicitly checking for it and doing something different.

任谁 2024-10-14 09:16:43

如果文件没有 ID3v2Tag 和 ID3v1Tag,Taglib 将在对象中创建一个“空”ID3v2Tag 和 ID3v1Tag。

Taglib create an "Empty" ID3v2Tag and ID3v1Tag in the object if the file do not have one.

稳稳的幸福 2024-10-14 09:16:43

我遇到了类似的问题,希望我找到了 ID3v1/ID3v2 存在检查的解决方法。

它的方法 virtual bool TagLib::Tag::isEmpty()常量

I am having simmilar problem and hopefully I've found workaround for ID3v1/ID3v2 presence checking.

It's method virtual bool TagLib::Tag::isEmpty() const

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文