Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

if_python3 でスクリプトローカル関数名が UnicodeDecodeError の原因になる #1209

Closed
ichizok opened this issue Nov 29, 2018 · 7 comments

Comments

@ichizok
Copy link
Member

ichizok commented Nov 29, 2018

質問・報告の内容

test.vim

function! s:f()
endfunction
let g:F = function('s:f')
py3 vim.bindeval('g:F').name

vim -Nu test.vim

Error detected while processing /tmp/test.vim:
line    4:
Traceback (most recent call last):
  File "<string>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x80 in position 0: invalid start byte

Vim関数の PyObject (FunctionObject) の name 属性は、関数名 (C文字列) を PyUnicode_Decode() に通した値に設定される。
スクリプトローカル関数の場合、関数名は get_expanded_name() で変換した形式 \x80\xfd で始まっており、invalid UTF-8 sequence であるため UnicodeDecodeError になる。

@ichizok
Copy link
Member Author

ichizok commented Nov 29, 2018

FunctionObject を作成する際、関数名 <SNR>1_fget_expanded_name()\x80\xfdR1_f の形式に変換していますが、これは必要でしょうか?
<SNR> のままで格納すると何か問題がある?

--- a/src/if_py_both.h
+++ b/src/if_py_both.h
@@ -2935,18 +2935,22 @@ FunctionNew(PyTypeObject *subtype, char_u *name, int argc, typval_T *argv,
                    N_("unnamed function %s does not exist"), name);
            return NULL;
        }
-       self->name = vim_strsave(name);
     }
     else
-       if ((self->name = get_expanded_name(name,
-                                   vim_strchr(name, AUTOLOAD_CHAR) == NULL))
-               == NULL)
+    {
+       char_u *p;
+
+       if ((p = get_expanded_name(name,
+                           vim_strchr(name, AUTOLOAD_CHAR) == NULL)) == NULL)
        {
            PyErr_FORMAT(PyExc_ValueError,
                    N_("function %s does not exist"), name);
            return NULL;
        }
+       vim_free(p);
+    }

+    self->name = vim_strsave(name);
     func_ref(self->name);
     self->argc = argc;
     self->argv = argv;

@ichizok
Copy link
Member Author

ichizok commented Nov 29, 2018

python側で \x80\xfd 使って構築された場合に対応できない。

py3 <<EOS
f = vim.Function(b'\x80\xfdR1_f')
EOS

@ichizok
Copy link
Member Author

ichizok commented Dec 3, 2018

https://github.com/vim/vim/compare/master...ichizok:fix/py3-vimfunc.diff

vim.Function() 構築時に prefix を "<SNR>" に変換する。

@ichizok
Copy link
Member Author

ichizok commented Dec 11, 2018

PRed.
vim/vim#3681

@h-east
Copy link
Member

h-east commented Dec 12, 2018

pが3byte以上あるかチェックしなくてもOKでしょうか?

vim/vim@9c7cefc#diff-e30f7b2f6336d31826de211f8f86f376R2951

if (p[0] == K_SPECIAL && p[1] == KS_EXTRA && p[2] == (int)KE_SNR)

@ichizok
Copy link
Member Author

ichizok commented Dec 12, 2018

その時点でpはNUL終端文字列であることが確実であるため、3byte以下なら途中で比較が失敗するので問題ないと思います。

@ichizok
Copy link
Member Author

ichizok commented Dec 23, 2018

8.1.0627
vim/vim@9123c0b

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants