From 39a21d749d9ff6c69b173900ec76b14ddc09626a Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 21 Sep 2025 06:16:20 +0800 Subject: [PATCH 1/2] vim-patch:9.1.1774: cannot calculate sha256 of a Blob Problem: cannot calculate sha256() of a Blob Solution: Change sha256() to accept a Blob or String argument (thinca). closes: vim/vim#18336 https://github.com/vim/vim/commit/4150283b837975152d36f87a2bb975e894bc965c Co-authored-by: thinca --- runtime/doc/vimfn.txt | 7 ++++--- runtime/lua/vim/_meta/vimfn.lua | 7 ++++--- src/nvim/eval.lua | 7 ++++--- src/nvim/eval/funcs.c | 21 +++++++++++++++------ test/old/testdir/test_sha256.vim | 12 ++++++++++++ 5 files changed, 39 insertions(+), 15 deletions(-) diff --git a/runtime/doc/vimfn.txt b/runtime/doc/vimfn.txt index 130a6a4832..ea191cb960 100644 --- a/runtime/doc/vimfn.txt +++ b/runtime/doc/vimfn.txt @@ -9468,12 +9468,13 @@ setwinvar({nr}, {varname}, {val}) *setwinvar()* Return: ~ (`any`) -sha256({string}) *sha256()* +sha256({expr}) *sha256()* Returns a String with 64 hex characters, which is the SHA256 - checksum of {string}. + checksum of {expr}. + {expr} is a String or a Blob. Parameters: ~ - • {string} (`string`) + • {expr} (`string`) Return: ~ (`string`) diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua index c56026b707..028a23d053 100644 --- a/runtime/lua/vim/_meta/vimfn.lua +++ b/runtime/lua/vim/_meta/vimfn.lua @@ -8631,11 +8631,12 @@ function vim.fn.settagstack(nr, dict, action) end function vim.fn.setwinvar(nr, varname, val) end --- Returns a String with 64 hex characters, which is the SHA256 ---- checksum of {string}. +--- checksum of {expr}. +--- {expr} is a String or a Blob. --- ---- @param string string +--- @param expr string --- @return string -function vim.fn.sha256(string) end +function vim.fn.sha256(expr) end --- Escape {string} for use as a shell command argument. --- diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index f921ac9d84..4b58eabed8 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -10419,13 +10419,14 @@ M.funcs = { base = 1, desc = [=[ Returns a String with 64 hex characters, which is the SHA256 - checksum of {string}. + checksum of {expr}. + {expr} is a String or a Blob. ]=], name = 'sha256', - params = { { 'string', 'string' } }, + params = { { 'expr', 'string' } }, returns = 'string', - signature = 'sha256({string})', + signature = 'sha256({expr})', }, shellescape = { args = { 1, 2 }, diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 1378fbc26b..54fd9d326a 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -7189,15 +7189,24 @@ static void f_settagstack(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } } -/// f_sha256 - sha256({string}) function +/// "sha256({expr})" function static void f_sha256(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - const char *p = tv_get_string(&argvars[0]); - const char *hash = sha256_bytes((const uint8_t *)p, strlen(p), NULL, 0); - - // make a copy of the hash (sha256_bytes returns a static buffer) - rettv->vval.v_string = xstrdup(hash); rettv->v_type = VAR_STRING; + rettv->vval.v_string = NULL; + + if (argvars[0].v_type == VAR_BLOB) { + blob_T *blob = argvars[0].vval.v_blob; + if (blob != NULL) { + const uint8_t *p = (uint8_t *)blob->bv_ga.ga_data; + int len = blob->bv_ga.ga_len; + rettv->vval.v_string = xstrdup(sha256_bytes(p, (size_t)len, NULL, 0)); + } + } else { + const char *p = tv_get_string(&argvars[0]); + const char *hash = sha256_bytes((const uint8_t *)p, strlen(p), NULL, 0); + rettv->vval.v_string = xstrdup(hash); + } } /// "shellescape({string})" function diff --git a/test/old/testdir/test_sha256.vim b/test/old/testdir/test_sha256.vim index b0941c60e3..9f4599bd73 100644 --- a/test/old/testdir/test_sha256.vim +++ b/test/old/testdir/test_sha256.vim @@ -19,4 +19,16 @@ function Test_sha256() " test for contains non-ascii char: call assert_equal('5f78c33274e43fa9de5659265c1d917e25c03722dcb0b8d27db8d5feaa813953', sha256("\xde\xad\xbe\xef")) + + " test for blob: + " empty blob + call assert_equal('e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855', sha256(0z)) + " blob with single byte + call assert_equal('ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb', sha256(0z61)) + " blob with "abc" + call assert_equal('ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad', sha256(0z616263)) + " blob with non-ascii bytes + call assert_equal('5f78c33274e43fa9de5659265c1d917e25c03722dcb0b8d27db8d5feaa813953', sha256(0zdeadbeef)) endfunction + +" vim: shiftwidth=2 sts=2 expandtab From a5955e5cc533100877ac2b0f65ac6127f844ea7f Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 21 Sep 2025 06:23:05 +0800 Subject: [PATCH 2/2] vim-patch:9.1.1778: sha256() treats empty blob and null blob differently Problem: sha256() treats empty blob and null blob differently (after 9.1.1774). Solution: Handle null blob the same as empty blob (zeertzjq). closes: vim/vim#18341 https://github.com/vim/vim/commit/2f3b7ea19a476a7637b6ad2c43e3a33755b1178b --- src/nvim/eval/funcs.c | 8 +++----- test/old/testdir/test_sha256.vim | 21 +++++++++++---------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 54fd9d326a..0f8d8b8d76 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -7197,11 +7197,9 @@ static void f_sha256(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) if (argvars[0].v_type == VAR_BLOB) { blob_T *blob = argvars[0].vval.v_blob; - if (blob != NULL) { - const uint8_t *p = (uint8_t *)blob->bv_ga.ga_data; - int len = blob->bv_ga.ga_len; - rettv->vval.v_string = xstrdup(sha256_bytes(p, (size_t)len, NULL, 0)); - } + const uint8_t *p = blob != NULL ? (uint8_t *)blob->bv_ga.ga_data : (uint8_t *)""; + int len = blob != NULL ? blob->bv_ga.ga_len : 0; + rettv->vval.v_string = xstrdup(sha256_bytes(p, (size_t)len, NULL, 0)); } else { const char *p = tv_get_string(&argvars[0]); const char *hash = sha256_bytes((const uint8_t *)p, strlen(p), NULL, 0); diff --git a/test/old/testdir/test_sha256.vim b/test/old/testdir/test_sha256.vim index 9f4599bd73..4c2380176e 100644 --- a/test/old/testdir/test_sha256.vim +++ b/test/old/testdir/test_sha256.vim @@ -5,24 +5,25 @@ source check.vim CheckFunction sha256 function Test_sha256() - " test for empty string: + " tests for string: + " empty string call assert_equal('e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855', sha256("")) - - "'test for 1 char: + " null string + call assert_equal('e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855', sha256(v:_null_string)) + " string with 1 char call assert_equal('ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb', sha256("a")) - " - "test for 3 chars: + " string with 3 chars call assert_equal('ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad', "abc"->sha256()) - - " test for contains meta char: + " string containing meta char call assert_equal('807eff6267f3f926a21d234f7b0cf867a86f47e07a532f15e8cc39ed110ca776', sha256("foo\nbar")) - - " test for contains non-ascii char: + " string containing non-ascii char call assert_equal('5f78c33274e43fa9de5659265c1d917e25c03722dcb0b8d27db8d5feaa813953', sha256("\xde\xad\xbe\xef")) - " test for blob: + " tests for blob: " empty blob call assert_equal('e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855', sha256(0z)) + " null blob + call assert_equal('e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855', sha256(v:_null_blob)) " blob with single byte call assert_equal('ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb', sha256(0z61)) " blob with "abc"