mirror of
				https://github.com/vim/vim.git
				synced 2025-10-30 09:47:20 -04:00 
			
		
		
		
	patch 9.0.1944: Vim9: function instruction pointer invalidated
Problem: Vim9: function instruction pointer invalidated Solution: Use the funcref index instead of the instruction pointer closes: #13178 closes: #13196 Signed-off-by: Christian Brabandt <cb@256bit.org> Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
This commit is contained in:
		
				
					committed by
					
						 Christian Brabandt
						Christian Brabandt
					
				
			
			
				
	
			
			
			
						parent
						
							91adcbdcc1
						
					
				
				
					commit
					a76fbe6e00
				
			| @@ -45,7 +45,7 @@ int generate_OLDSCRIPT(cctx_T *cctx, isntype_T isn_type, char_u *name, int sid, | ||||
| int generate_VIM9SCRIPT(cctx_T *cctx, isntype_T isn_type, int sid, int idx, type_T *type); | ||||
| int generate_NEWLIST(cctx_T *cctx, int count, int use_null); | ||||
| int generate_NEWDICT(cctx_T *cctx, int count, int use_null); | ||||
| int generate_FUNCREF(cctx_T *cctx, ufunc_T *ufunc, class_T *cl, int fi, isn_T **isnp); | ||||
| int generate_FUNCREF(cctx_T *cctx, ufunc_T *ufunc, class_T *cl, int fi, int *isn_idx); | ||||
| int generate_NEWFUNC(cctx_T *cctx, char_u *lambda_name, char_u *func_name); | ||||
| int generate_DEF(cctx_T *cctx, char_u *name, size_t len); | ||||
| int generate_JUMP(cctx_T *cctx, jumpwhen_T when, int where); | ||||
|   | ||||
| @@ -4636,6 +4636,56 @@ def Test_free_type_before_use() | ||||
|   v9.CheckScriptSuccess(lines) | ||||
| enddef | ||||
|  | ||||
| " The following complicated script used to cause an internal error (E340) | ||||
| " because the funcref instruction memory was referenced after the instruction | ||||
| " memory was reallocated (Github issue #13178) | ||||
| def Test_refer_funcref_instr_after_realloc() | ||||
|   var lines =<< trim END | ||||
|     vim9script | ||||
|     def A(d: bool) | ||||
|       var e = abs(0) | ||||
|       var f = &emoji | ||||
|       &emoji = true | ||||
|       if ['', '', '']->index('xxx') == 0 | ||||
|         eval 0 + 0 | ||||
|       endif | ||||
|       if &filetype == 'xxx' | ||||
|         var g = abs(0) | ||||
|         while g > 0 | ||||
|           if getline(g) == '' | ||||
|             break | ||||
|           endif | ||||
|           --g | ||||
|         endwhile | ||||
|         if g == 0 | ||||
|           return | ||||
|         endif | ||||
|         if d | ||||
|           feedkeys($'{g}G') | ||||
|           g = abs(0) | ||||
|         endif | ||||
|         var h = abs(0) | ||||
|         var i = abs(0) | ||||
|         var j = abs(0) | ||||
|         while j < 0 | ||||
|           if abs(0) < h && getline(j) != '' | ||||
|           break | ||||
|           endif | ||||
|           ++j | ||||
|         endwhile | ||||
|         feedkeys($'{g}G{j}G') | ||||
|         return | ||||
|       endif | ||||
|       def B() | ||||
|       enddef | ||||
|       def C() | ||||
|       enddef | ||||
|     enddef | ||||
|     A(false) | ||||
|   END | ||||
|   v9.CheckScriptSuccess(lines) | ||||
| enddef | ||||
|  | ||||
| " Keep this last, it messes up highlighting. | ||||
| def Test_substitute_cmd() | ||||
|   new | ||||
|   | ||||
| @@ -699,6 +699,8 @@ static char *(features[]) = | ||||
|  | ||||
| static int included_patches[] = | ||||
| {   /* Add new patch number below this line */ | ||||
| /**/ | ||||
|     1944, | ||||
| /**/ | ||||
|     1943, | ||||
| /**/ | ||||
|   | ||||
| @@ -1029,7 +1029,7 @@ compile_nested_function(exarg_T *eap, cctx_T *cctx, garray_T *lines_to_free) | ||||
|     ufunc_T	*ufunc; | ||||
|     int		r = FAIL; | ||||
|     compiletype_T   compile_type; | ||||
|     isn_T	*funcref_isn = NULL; | ||||
|     int		funcref_isn_idx = -1; | ||||
|     lvar_T	*lvar = NULL; | ||||
|  | ||||
|     if (eap->forceit) | ||||
| @@ -1148,7 +1148,7 @@ compile_nested_function(exarg_T *eap, cctx_T *cctx, garray_T *lines_to_free) | ||||
| 					    ASSIGN_CONST, ufunc->uf_func_type); | ||||
| 	if (lvar == NULL) | ||||
| 	    goto theend; | ||||
| 	if (generate_FUNCREF(cctx, ufunc, NULL, 0, &funcref_isn) == FAIL) | ||||
| 	if (generate_FUNCREF(cctx, ufunc, NULL, 0, &funcref_isn_idx) == FAIL) | ||||
| 	    goto theend; | ||||
| 	r = generate_STORE(cctx, ISN_STORE, lvar->lv_idx, NULL); | ||||
|     } | ||||
| @@ -1178,8 +1178,12 @@ compile_nested_function(exarg_T *eap, cctx_T *cctx, garray_T *lines_to_free) | ||||
| #endif | ||||
|  | ||||
|     // If a FUNCREF instruction was generated, set the index after compiling. | ||||
|     if (funcref_isn != NULL && ufunc->uf_def_status == UF_COMPILED) | ||||
|     if (funcref_isn_idx != -1 && ufunc->uf_def_status == UF_COMPILED) | ||||
|     { | ||||
| 	isn_T	*funcref_isn = ((isn_T *)cctx->ctx_instr.ga_data) + | ||||
| 							funcref_isn_idx; | ||||
| 	funcref_isn->isn_arg.funcref.fr_dfunc_idx = ufunc->uf_dfunc_idx; | ||||
|     } | ||||
|  | ||||
| theend: | ||||
|     vim_free(lambda_name); | ||||
|   | ||||
| @@ -1378,7 +1378,9 @@ generate_NEWDICT(cctx_T *cctx, int count, int use_null) | ||||
|  * Generate an ISN_FUNCREF instruction. | ||||
|  * For "obj.Method" "cl" is the class of the object (can be an interface or a | ||||
|  * base class) and "fi" the index of the method on that class. | ||||
|  * "isnp" is set to the instruction, so that fr_dfunc_idx can be set later. | ||||
|  * "isn_idx" is set to the index of the instruction, so that fr_dfunc_idx can | ||||
|  * be set later.  The index is used instead of a pointer to the instruction | ||||
|  * because the instruction memory can be reallocated. | ||||
|  */ | ||||
|     int | ||||
| generate_FUNCREF( | ||||
| @@ -1386,7 +1388,7 @@ generate_FUNCREF( | ||||
| 	ufunc_T	    *ufunc, | ||||
| 	class_T	    *cl, | ||||
| 	int	    fi, | ||||
| 	isn_T	    **isnp) | ||||
| 	int	    *isn_idx) | ||||
| { | ||||
|     isn_T	    *isn; | ||||
|     type_T	    *type; | ||||
| @@ -1397,8 +1399,9 @@ generate_FUNCREF( | ||||
|     RETURN_OK_IF_SKIP(cctx); | ||||
|     if ((isn = generate_instr(cctx, ISN_FUNCREF)) == NULL) | ||||
| 	return FAIL; | ||||
|     if (isnp != NULL) | ||||
| 	*isnp = isn; | ||||
|     if (isn_idx != NULL) | ||||
| 	// save the index of the new instruction | ||||
| 	*isn_idx = cctx->ctx_instr.ga_len - 1; | ||||
|  | ||||
|     has_vars = get_loop_var_info(cctx, &loopinfo); | ||||
|     if (ufunc->uf_def_status == UF_NOT_COMPILED || has_vars || cl != NULL) | ||||
| @@ -1419,7 +1422,7 @@ generate_FUNCREF( | ||||
| 	extra->fre_func_name = vim_strsave(ufunc->uf_name); | ||||
|     if (ufunc->uf_def_status != UF_NOT_COMPILED && cl == NULL) | ||||
|     { | ||||
| 	if (isnp == NULL && ufunc->uf_def_status == UF_TO_BE_COMPILED) | ||||
| 	if (isn_idx == NULL && ufunc->uf_def_status == UF_TO_BE_COMPILED) | ||||
| 	    // compile the function now, we need the uf_dfunc_idx value | ||||
| 	    (void)compile_def_function(ufunc, FALSE, CT_NONE, NULL); | ||||
| 	isn->isn_arg.funcref.fr_dfunc_idx = ufunc->uf_dfunc_idx; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user