2

このエッジケースでの glShaderSource の動作が正しいかどうか疑問に思っています:

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

どこ:

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

したがって、基本的に OpenGL は長さ 0 の文字列を読み取るように指示されますが、長さがわかっている場合でも strlen を呼び出します。仕様では、OpenGL は、4 番目の引数として NULL を渡すか、指定された長さが 0 より小さい場合にのみ、文字列がゼロで終了していると想定すると述べています。strlen が呼び出されるのはなぜですか? この動作は正しいですか?

4

1 に答える 1

2

OpenGL 4 リファレンス ページに示されているように、OpenGL ドライバーがシェーダー データが null で終了していると想定できる状況が 2 つあります。

glShaderSourceドキュメントから:

lengthである場合NULL、各文字列は null で終了すると見なされますlengthが 以外の値の場合、NULLの対応する各要素の文字列の長さを含む配列を指しstringます。長さ配列の各要素には、対応する文字列の長さ (null 文字は文字列の長さの一部としてカウントされません)、または文字列が null で終了することを示す 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 仕様に違反しており、プログラムのクラッシュを引き起こす可能性があります。ユーザーが提供した文字列が渡されます。strlenglShaderSource

少し関係の深い話ですが、明示的な長さで提供される文字列内にヌル文字が存在する場合に何が起こるかは、標準では指定されていません。つまり、実装は好きなように行うことができます。文字列を null で終了する (したがって、その後のすべてをスキップする) として扱うか、null 文字を無視するか、または GLSL によって空白として認識される文字の中にないため、シェーダーのコンパイルが失敗する可能性があります。

于 2013-11-01T00:23:19.163 に答える