Files
ncnn/tests/test_gpu.cpp
lazypool 4366038c23 fix spirv compile failure diagnostics read past shader buffer (#6882)
* fix spirv compile failure diagnostics read past shader buffer (#6881)

the shader source slice passed to glslang (comp_datas[3]) is not
null-terminated, since the .comp_data arrays generated by
ncnn_generate_shader_comp_header.cmake are hex-encoded without a
trailing 0x00. the error-printing path in compile_spirv_module()
scanned it with strchr() and checked *p != '\0', causing an
out-of-bounds read and garbled diagnostics whenever a shader fails
to compile.

bound the scan with memchr() using the known source length and print
the trailing partial line with %.*s instead of relying on
null-termination. verified with asan: before, a broken non-null-
terminated shader source reports a stack-buffer-overflow in
compile_spirv_module(); after, the error path prints correctly with
no overrun.

* fix bounded shader version parsing and add regression tests

---------

Signed-off-by: lazypool <lazypool@proton.me>
Co-authored-by: Marcin Sochacki <136440930+marcin-sochacki@users.noreply.github.com>
Co-authored-by: nihui <nihuini@tencent.com>
2026-09-15 21:49:34 +08:00

75 lines
2.5 KiB
C++

// Copyright 2026 Tencent
// SPDX-License-Identifier: BSD-3-Clause
#include "gpu.h"
#include "testutil.h"
#include <stdio.h>
#include <string.h>
static int test_compile_spirv_module(const char* source, int expected, int comp_data_size = -1)
{
const int source_size = strlen(source);
char* comp_data = new char[source_size];
memcpy(comp_data, source, source_size);
if (comp_data_size == -1)
comp_data_size = source_size;
ncnn::Option opt;
opt.use_fp16_packed = false;
opt.use_fp16_storage = false;
opt.use_fp16_arithmetic = false;
std::vector<uint32_t> spirv;
int ret = ncnn::compile_spirv_module(comp_data, comp_data_size, opt, spirv);
delete[] comp_data;
if (ret != expected)
{
fprintf(stderr, "test_compile_spirv_module failed ret=%d expected=%d comp_data_size=%d source=%s\n", ret, expected, comp_data_size, source);
return -1;
}
return 0;
}
static int test_compile_spirv_module_0()
{
return 0
|| test_compile_spirv_module("#version 450\nlayout(local_size_x = 1) in;\nvoid main() {}", 0)
|| test_compile_spirv_module("#version 450\nlayout(local_size_x = 1) in;\nvoid main() {}\n", 0)
|| test_compile_spirv_module("#version 450\r\nlayout(local_size_x = 1) in;\r\nvoid main() {}", 0)
|| test_compile_spirv_module("#version 450\rlayout(local_size_x = 1) in;\rvoid main() {}", 0)
|| test_compile_spirv_module("// leading comment\n#version\t450\n \t\r\nlayout(local_size_x = 1) in;\nvoid main() {}", 0)
|| test_compile_spirv_module("#version 450\n", 0)
|| test_compile_spirv_module("#version 450\n \t\r\n", 0)
|| test_compile_spirv_module("#version 450\n #error outside source", 0, 13);
}
static int test_compile_spirv_module_1()
{
return 0
|| test_compile_spirv_module("", -1)
|| test_compile_spirv_module("#version", -1)
|| test_compile_spirv_module("#version \t", -1)
|| test_compile_spirv_module("#version +", -1)
|| test_compile_spirv_module("#version nope\n", -1)
|| test_compile_spirv_module("void main() {}", -1)
|| test_compile_spirv_module("x#version 450\n", -1)
|| test_compile_spirv_module("#version 450\n#error test", -1)
|| test_compile_spirv_module("#version 450\n#error test\n", -1);
}
int main()
{
SRAND(7767517);
if (ncnn::get_gpu_count() == 0)
return 0;
return 0
|| test_compile_spirv_module_0()
|| test_compile_spirv_module_1();
}