有两种情况允许 OpenGL 驱动程序假定着色器数据为空终止,如 OpenGL 4 参考页中所述。
来自glShaderSource文档:
如果length
是NULL
,则假定每个字符串都以空值结尾。如果length
是 以外的值NULL
,则它指向一个数组,该数组包含 的每个对应元素的字符串长度string
。长度数组中的每个元素可能包含相应字符串的长度(空字符不计入字符串长度的一部分)或小于 0 的值以指示字符串以空字符结尾。此时不扫描或解析源代码字符串;它们被简单地复制到指定的着色器对象中。
由于所强调的约束都不适用于所提出的情况,因此不允许驱动程序strlen
直接在提供的数据上使用不安全的 c-string 函数。如果是这样,它很可能会在数据结束后运行,并可能最终访问未分配的内存,从而使程序崩溃。
但是,允许驱动程序将数据复制到安全缓冲区中,然后调用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 识别为空格的字符中。