changeset 35088:30cc85d355c1 v9.1.0385

patch 9.1.0385: Vim9: crash with null_class and null_object Commit: https://github.com/vim/vim/commit/b2e42b9be0ffa193ef32ad5a5846ef46f5cc4e8c Author: Yegappan Lakshmanan <yegappan@yahoo.com> Date: Wed May 1 11:44:17 2024 +0200 patch 9.1.0385: Vim9: crash with null_class and null_object Problem: Vim9: crash with null_class and null_object (Aliaksei Budavei) Solution: Handle null_class and null_object correctly (Yegappan Lakshmanan) fixes: #14678 closes: #14681 Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
author Christian Brabandt <cb@256bit.org>
date Wed, 01 May 2024 12:00:06 +0200
parents 0a5114d897d6
children f334642b40b4
files src/eval.c src/evalfunc.c src/testdir/test_vim9_class.vim src/version.c src/vim9type.c
diffstat 5 files changed, 67 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/src/eval.c
+++ b/src/eval.c
@@ -6403,9 +6403,9 @@ echo_string_core(
 	    {
 		class_T *cl = tv->vval.v_class;
 		char *s = "class";
-		if (IS_INTERFACE(cl))
+		if (cl && IS_INTERFACE(cl))
 		    s = "interface";
-		else if (IS_ENUM(cl))
+		else if (cl && IS_ENUM(cl))
 		    s = "enum";
 		size_t len = STRLEN(s) + 1 +
 		    (cl == NULL ? 9 : STRLEN(cl->class_name)) + 1;
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -11497,7 +11497,7 @@ f_type(typval_T *argvars, typval_T *rett
 	case VAR_CLASS:
 	    {
 		class_T *cl = argvars[0].vval.v_class;
-		if (IS_ENUM(cl))
+		if (cl && IS_ENUM(cl))
 		    n = VAR_TYPE_ENUM;
 		else
 		    n = VAR_TYPE_CLASS;
@@ -11505,11 +11505,18 @@ f_type(typval_T *argvars, typval_T *rett
 	    }
 	case VAR_OBJECT:
 	    {
-		class_T *cl = argvars[0].vval.v_object->obj_class;
-		if (IS_ENUM(cl))
-		    n = VAR_TYPE_ENUMVALUE;
+		object_T *obj = argvars[0].vval.v_object;
+
+		if (obj == NULL)
+		    n = VAR_TYPE_OBJECT;
 		else
-		    n = VAR_TYPE_OBJECT;
+		{
+		    class_T *cl = argvars[0].vval.v_object->obj_class;
+		    if (IS_ENUM(cl))
+			n = VAR_TYPE_ENUMVALUE;
+		    else
+			n = VAR_TYPE_OBJECT;
+		}
 		break;
 	    }
 	case VAR_UNKNOWN:
--- a/src/testdir/test_vim9_class.vim
+++ b/src/testdir/test_vim9_class.vim
@@ -545,6 +545,52 @@ def Test_using_null_class()
     @_ = null_class.member
   END
   v9.CheckDefExecAndScriptFailure(lines, ['E715: Dictionary required', 'E1363: Incomplete type'])
+
+  # Test for using a null class as a value
+  lines =<< trim END
+    vim9script
+    echo empty(null_class)
+  END
+  v9.CheckSourceFailure(lines, 'E1405: Class "" cannot be used as a value', 2)
+
+  # Test for using a null class with string()
+  lines =<< trim END
+    vim9script
+    assert_equal('class [unknown]', string(null_class))
+  END
+  v9.CheckSourceSuccess(lines)
+
+  # Test for using a null class with string()
+  lines =<< trim END
+    vim9script
+    assert_equal(12, type(null_class))
+    assert_equal('class<Unknown>', typename(null_class))
+  END
+  v9.CheckSourceSuccess(lines)
+enddef
+
+def Test_using_null_object()
+  # Test for using a null object as a value
+  var lines =<< trim END
+    vim9script
+    assert_equal(1, empty(null_object))
+  END
+  v9.CheckSourceSuccess(lines)
+
+  # Test for using a null object with string()
+  lines =<< trim END
+    vim9script
+    assert_equal('object of [unknown]', string(null_object))
+  END
+  v9.CheckSourceSuccess(lines)
+
+  # Test for using a null object with string()
+  lines =<< trim END
+    vim9script
+    assert_equal(13, type(null_object))
+    assert_equal('object<Unknown>', typename(null_object))
+  END
+  v9.CheckSourceSuccess(lines)
 enddef
 
 def Test_class_interface_wrong_end()
--- a/src/version.c
+++ b/src/version.c
@@ -705,6 +705,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    385,
+/**/
     384,
 /**/
     383,
--- a/src/vim9type.c
+++ b/src/vim9type.c
@@ -2091,10 +2091,12 @@ check_typval_is_value(typval_T *tv)
 	case VAR_CLASS:
 	    {
 		class_T *cl = tv->vval.v_class;
-		if (IS_ENUM(cl))
-		    semsg(_(e_using_enum_as_value_str), cl->class_name);
+		char_u *class_name = (cl == NULL) ? (char_u *)""
+							: cl->class_name;
+		if (cl && IS_ENUM(cl))
+		    semsg(_(e_using_enum_as_value_str), class_name);
 		else
-		    semsg(_(e_using_class_as_value_str), cl->class_name);
+		    semsg(_(e_using_class_as_value_str), class_name);
 	    }
 	    return FAIL;