commit 4f44705a479d7194ec1a1c0efec7bd31a91acbb2
parent 992eaac08218c037ffa8980f36a628f5b293355b
Author: bfredl <bjorn.linse@gmail.com>
Date: Fri, 16 Jan 2026 09:14:54 +0100
Merge pull request #37189 from bfredl/zigsafe
ci: test -Doptimize=ReleaseSafe
Diffstat:
4 files changed, 34 insertions(+), 28 deletions(-)
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
@@ -209,6 +209,8 @@ jobs:
runs-on: ubuntu-24.04
timeout-minutes: 45
name: build using zig build (linux)
+ env:
+ OPTS: -Doptimize=ReleaseSafe
steps:
- uses: actions/checkout@v6
- uses: mlugg/setup-zig@v2
@@ -216,10 +218,10 @@ jobs:
version: 0.15.2
- run: sudo apt-get install -y inotify-tools
- - run: zig build test_nlua0
- - run: zig build nvim_bin && ./zig-out/bin/nvim --version
- - run: zig build unittest
- - run: zig build functionaltest
+ - run: zig build $OPTS test_nlua0
+ - run: zig build $OPTS nvim_bin && ./zig-out/bin/nvim --version
+ - run: zig build $OPTS unittest
+ - run: zig build $OPTS functionaltest
# `zig build` uses a lua script for doctags in order to support cross-compiling
# compare with the builtin generator that they match
- run: cd runtime; ../zig-out/bin/nvim -u NONE -i NONE -e --headless -c "helptags ++t doc" -c quit
diff --git a/build.zig b/build.zig
@@ -141,10 +141,12 @@ pub fn build(b: *std.Build) !void {
.target = target,
.optimize = optimize,
}) else null;
+
// TODO(bfredl): fix upstream bugs with UBSAN
+ const optimize_ts = .ReleaseFast;
const treesitter = if (system_integration_options.tree_sitter) null else b.lazyDependency("treesitter", .{
.target = target,
- .optimize = .ReleaseFast,
+ .optimize = optimize_ts,
});
const nlua0 = try build_lua.build_nlua0(
@@ -623,31 +625,31 @@ pub fn build(b: *std.Build) !void {
xxd_exe.linkLibC();
test_deps.dependOn(&b.addInstallArtifact(xxd_exe, .{}).step);
- const parser_c = b.dependency("treesitter_c", .{ .target = target, .optimize = optimize });
- test_deps.dependOn(add_ts_parser(b, "c", parser_c.path("."), false, target, optimize, .test_));
- install.dependOn(add_ts_parser(b, "c", parser_c.path("."), false, target, optimize, .install));
+ const parser_c = b.dependency("treesitter_c", .{ .target = target, .optimize = optimize_ts });
+ test_deps.dependOn(add_ts_parser(b, "c", parser_c.path("."), false, target, optimize_ts, .test_));
+ install.dependOn(add_ts_parser(b, "c", parser_c.path("."), false, target, optimize_ts, .install));
- const parser_markdown = b.dependency("treesitter_markdown", .{ .target = target, .optimize = optimize });
- test_deps.dependOn(add_ts_parser(b, "markdown", parser_markdown.path("tree-sitter-markdown/"), true, target, optimize, .test_));
- install.dependOn(add_ts_parser(b, "markdown", parser_markdown.path("tree-sitter-markdown/"), true, target, optimize, .install));
- test_deps.dependOn(add_ts_parser(b, "markdown_inline", parser_markdown.path("tree-sitter-markdown-inline/"), true, target, optimize, .test_));
- install.dependOn(add_ts_parser(b, "markdown_inline", parser_markdown.path("tree-sitter-markdown-inline/"), true, target, optimize, .install));
+ const parser_markdown = b.dependency("treesitter_markdown", .{ .target = target, .optimize = optimize_ts });
+ test_deps.dependOn(add_ts_parser(b, "markdown", parser_markdown.path("tree-sitter-markdown/"), true, target, optimize_ts, .test_));
+ install.dependOn(add_ts_parser(b, "markdown", parser_markdown.path("tree-sitter-markdown/"), true, target, optimize_ts, .install));
+ test_deps.dependOn(add_ts_parser(b, "markdown_inline", parser_markdown.path("tree-sitter-markdown-inline/"), true, target, optimize_ts, .test_));
+ install.dependOn(add_ts_parser(b, "markdown_inline", parser_markdown.path("tree-sitter-markdown-inline/"), true, target, optimize_ts, .install));
- const parser_vim = b.dependency("treesitter_vim", .{ .target = target, .optimize = optimize });
- test_deps.dependOn(add_ts_parser(b, "vim", parser_vim.path("."), true, target, optimize, .test_));
- install.dependOn(add_ts_parser(b, "vim", parser_vim.path("."), true, target, optimize, .install));
+ const parser_vim = b.dependency("treesitter_vim", .{ .target = target, .optimize = optimize_ts });
+ test_deps.dependOn(add_ts_parser(b, "vim", parser_vim.path("."), true, target, optimize_ts, .test_));
+ install.dependOn(add_ts_parser(b, "vim", parser_vim.path("."), true, target, optimize_ts, .install));
- const parser_vimdoc = b.dependency("treesitter_vimdoc", .{ .target = target, .optimize = optimize });
- test_deps.dependOn(add_ts_parser(b, "vimdoc", parser_vimdoc.path("."), false, target, optimize, .test_));
- install.dependOn(add_ts_parser(b, "vimdoc", parser_vimdoc.path("."), false, target, optimize, .install));
+ const parser_vimdoc = b.dependency("treesitter_vimdoc", .{ .target = target, .optimize = optimize_ts });
+ test_deps.dependOn(add_ts_parser(b, "vimdoc", parser_vimdoc.path("."), false, target, optimize_ts, .test_));
+ install.dependOn(add_ts_parser(b, "vimdoc", parser_vimdoc.path("."), false, target, optimize_ts, .install));
- const parser_lua = b.dependency("treesitter_lua", .{ .target = target, .optimize = optimize });
- test_deps.dependOn(add_ts_parser(b, "lua", parser_lua.path("."), true, target, optimize, .test_));
- install.dependOn(add_ts_parser(b, "lua", parser_lua.path("."), true, target, optimize, .install));
+ const parser_lua = b.dependency("treesitter_lua", .{ .target = target, .optimize = optimize_ts });
+ test_deps.dependOn(add_ts_parser(b, "lua", parser_lua.path("."), true, target, optimize_ts, .test_));
+ install.dependOn(add_ts_parser(b, "lua", parser_lua.path("."), true, target, optimize_ts, .install));
- const parser_query = b.dependency("treesitter_query", .{ .target = target, .optimize = optimize });
- test_deps.dependOn(add_ts_parser(b, "query", parser_query.path("."), false, target, optimize, .test_));
- install.dependOn(add_ts_parser(b, "query", parser_query.path("."), false, target, optimize, .install));
+ const parser_query = b.dependency("treesitter_query", .{ .target = target, .optimize = optimize_ts });
+ test_deps.dependOn(add_ts_parser(b, "query", parser_query.path("."), false, target, optimize_ts, .test_));
+ install.dependOn(add_ts_parser(b, "query", parser_query.path("."), false, target, optimize_ts, .install));
var unit_headers: ?[]const LazyPath = null;
if (support_unittests) {
diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c
@@ -2029,7 +2029,9 @@ dictitem_T *tv_dict_item_alloc_len(const char *const key, const size_t key_len)
FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
FUNC_ATTR_MALLOC
{
- dictitem_T *const di = xmalloc(offsetof(dictitem_T, di_key) + key_len + 1);
+ // Allocating a struct smaller than its static size is UB (#37160)
+ dictitem_T *const di = xmalloc(MAX(sizeof(dictitem_T),
+ offsetof(dictitem_T, di_key) + key_len + 1));
memcpy(di->di_key, key, key_len);
di->di_key[key_len] = NUL;
di->di_flags = DI_FLAGS_ALLOC;
diff --git a/test/unit/eval/testutil.lua b/test/unit/eval/testutil.lua
@@ -413,7 +413,7 @@ local function alloc_len(len, get_ptr)
if type(len) == 'string' or type(len) == 'table' then
return #len
elseif len == nil then
- return eval.strlen(get_ptr())
+ return tonumber(eval.strlen(get_ptr()))
else
return len
end
@@ -435,7 +435,7 @@ local alloc_logging_t = {
end)
return {
func = 'malloc',
- args = { ffi.offsetof('dictitem_T', 'di_key') + size + 1 },
+ args = { math.max(ffi.sizeof('dictitem_T'), ffi.offsetof('dictitem_T', 'di_key') + size + 1) },
ret = void(di),
}
end,