【问题标题】:glShaderSource with length set to 0长度设置为 0 的 glShaderSource
【发布时间】:2013-10-31 21:03:47
【问题描述】:

我想知道 glShaderSource 在这种边缘情况下的行为是否正确:

glShaderSource(shader, 1, (const char**)ptr, length) 

地点:

char * tmp = (char*)alloca(0);
const char ** ptr = &tmp;
GLint length[1] = { 0 };

所以基本上 OpenGL 被告知要读取一个长度为零的字符串,但它仍然会调用 strlen ,即使它知道它的长度。在规范中,它说只有当我们将 NULL 作为第四个参数传递或给定长度小于 0 时,OpenGL 才会假定字符串为零终止。为什么调用 strlen?这种行为正确吗?

【问题讨论】:

  • 零长度 c 字符串的实际长度为 1 个字节,因此您应该使用 alloca(1)
  • @bcrist:这里 GL 期望的长度是没有字符串终止标记的 crachter 数。
  • 啊,那么是的,这可能是您的驱动程序实现中的错误
  • 是的,您的驱动程序似乎不符合规范。您是否有理由需要支持非零终止字符串?一般来说,总是要求字符串以空值结尾是个好主意,因为在测试库等时很容易错过这种类型的错误。
  • 在 Haskell OpenGL 绑定中,如果你读取一个空文件,你会得到一个空的 ByteString。如果你将该 ByteString 传递给 OpenGL,alloca 会以 0 长度被调用,并且指针会被传递给 glShaderSource。

标签: c opengl


【解决方案1】:

有两种情况允许 OpenGL 驱动程序假定着色器数据为空终止,如 OpenGL 4 参考页中所述。

来自glShaderSource 文档:

如果lengthNULL,则假定每个字符串都以空值结尾。 如果lengthNULL 以外的值,则它指向一个包含 string 的每个对应元素的字符串长度。每个 长度数组中的元素可能包含对应的长度 字符串(空字符不计入字符串长度的一部分) 或小于 0 的值表示字符串为空终止。 此时不扫描或解析源代码字符串;他们是 简单地复制到指定的着色器对象中。

由于对所提出的情况没有任何强调的约束,因此不允许驱动程序直接在提供的数据上使用不安全的 c 字符串函数,例如 strlen。如果是这样,它很可能会跑过数据的末尾,最终可能会访问未分配的内存,从而导致程序崩溃。

但是,驱动程序允许将数据复制到安全缓冲区中,然后调用strlen。例如,一个实现可能包含这样的代码:

void glShaderSource(GLuint shader,
                    GLsizei count,
                    const GLchar **string,
                    const GLint *length)
{
    if (length == NULL) { /* each string is null terminated. */ }
    else for (GLsizei i = 0; i < count; ++i)
    {
        size_t len = length[i];

        if (len < 0) { /* this string is null terminated. */ }
        else
        {
            char* buffer = (char*)malloc(len + 1);
            memcpy(buffer, string[i], len);
            buffer[len] = 0;

            size_t str_len = strlen(buffer);
            // This is OK, because we copied the
            // data into a null terminated buffer.

            free(buffer);
        }
    }
}

因此,在这种情况下,如果您的驱动程序实际上是在用户提供的指针上调用 strlen,那么它违反了 OpenGL 规范,并且可能导致程序崩溃,但只是看到 strlen 正在被调用glShaderSource 并不一定意味着它是传递给它的用户提供的字符串之一。

稍微有点切题,当标准未指定提供显式长度的字符串中存在空字符时会发生什么,这意味着实现可以随心所欲。它可以将字符串视为以空字符结尾(从而跳过其后的所有内容)、忽略空字符,或者导致着色器编译失败,因为它不在 GLSL 识别为空格的字符中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-07-27
    • 2012-07-12
    • 2018-05-25
    • 2021-01-30
    • 2017-11-10
    • 1970-01-01
    相关资源
    最近更新 更多