comparison src/vim9compile.c @ 25656:fe7f45e2895e v8.2.3364

patch 8.2.3364: Vim9: crash when :for is skipped Commit: https://github.com/vim/vim/commit/bebf06954e1c801870b57e06ab03151c2654d079 Author: rbtnn <naru123456789@gmail.com> Date: Sat Aug 21 17:26:50 2021 +0200 patch 8.2.3364: Vim9: crash when :for is skipped Problem: Vim9: crash when :for is skipped. Solution: Skip more code generation. (Naruhiko Nishino, closes https://github.com/vim/vim/issues/8777)
author Bram Moolenaar <Bram@vim.org>
date Sat, 21 Aug 2021 17:30:03 +0200
parents 6ed39aa92cb9
children 483b40e87ca5
comparison
equal deleted inserted replaced
25655:cf7cd75766d9 25656:fe7f45e2895e
8039 drop_scope(cctx); 8039 drop_scope(cctx);
8040 return NULL; 8040 return NULL;
8041 } 8041 }
8042 arg_end = arg; 8042 arg_end = arg;
8043 8043
8044 // If we know the type of "var" and it is a not a supported type we can 8044 if (cctx->ctx_skip != SKIP_YES)
8045 // give an error now. 8045 {
8046 vartype = ((type_T **)stack->ga_data)[stack->ga_len - 1]; 8046 // If we know the type of "var" and it is a not a supported type we can
8047 if (vartype->tt_type != VAR_LIST && vartype->tt_type != VAR_STRING 8047 // give an error now.
8048 vartype = ((type_T **)stack->ga_data)[stack->ga_len - 1];
8049 if (vartype->tt_type != VAR_LIST && vartype->tt_type != VAR_STRING
8048 && vartype->tt_type != VAR_BLOB && vartype->tt_type != VAR_ANY) 8050 && vartype->tt_type != VAR_BLOB && vartype->tt_type != VAR_ANY)
8049 { 8051 {
8050 semsg(_(e_for_loop_on_str_not_supported), 8052 semsg(_(e_for_loop_on_str_not_supported),
8051 vartype_name(vartype->tt_type)); 8053 vartype_name(vartype->tt_type));
8052 drop_scope(cctx);
8053 return NULL;
8054 }
8055
8056 if (vartype->tt_type == VAR_STRING)
8057 item_type = &t_string;
8058 else if (vartype->tt_type == VAR_BLOB)
8059 item_type = &t_number;
8060 else if (vartype->tt_type == VAR_LIST
8061 && vartype->tt_member->tt_type != VAR_ANY)
8062 {
8063 if (!var_list)
8064 item_type = vartype->tt_member;
8065 else if (vartype->tt_member->tt_type == VAR_LIST
8066 && vartype->tt_member->tt_member->tt_type != VAR_ANY)
8067 // TODO: should get the type for each lhs
8068 item_type = vartype->tt_member->tt_member;
8069 }
8070
8071 // CMDMOD_REV must come before the FOR instruction.
8072 generate_undo_cmdmods(cctx);
8073
8074 // "for_end" is set when ":endfor" is found
8075 scope->se_u.se_for.fs_top_label = current_instr_idx(cctx);
8076
8077 generate_FOR(cctx, loop_lvar->lv_idx);
8078
8079 arg = arg_start;
8080 if (var_list)
8081 {
8082 generate_UNPACK(cctx, var_count, semicolon);
8083 arg = skipwhite(arg + 1); // skip white after '['
8084
8085 // the list item is replaced by a number of items
8086 if (GA_GROW_FAILS(stack, var_count - 1))
8087 {
8088 drop_scope(cctx); 8054 drop_scope(cctx);
8089 return NULL; 8055 return NULL;
8090 } 8056 }
8091 --stack->ga_len; 8057
8058 if (vartype->tt_type == VAR_STRING)
8059 item_type = &t_string;
8060 else if (vartype->tt_type == VAR_BLOB)
8061 item_type = &t_number;
8062 else if (vartype->tt_type == VAR_LIST
8063 && vartype->tt_member->tt_type != VAR_ANY)
8064 {
8065 if (!var_list)
8066 item_type = vartype->tt_member;
8067 else if (vartype->tt_member->tt_type == VAR_LIST
8068 && vartype->tt_member->tt_member->tt_type != VAR_ANY)
8069 // TODO: should get the type for each lhs
8070 item_type = vartype->tt_member->tt_member;
8071 }
8072
8073 // CMDMOD_REV must come before the FOR instruction.
8074 generate_undo_cmdmods(cctx);
8075
8076 // "for_end" is set when ":endfor" is found
8077 scope->se_u.se_for.fs_top_label = current_instr_idx(cctx);
8078
8079 generate_FOR(cctx, loop_lvar->lv_idx);
8080
8081 arg = arg_start;
8082 if (var_list)
8083 {
8084 generate_UNPACK(cctx, var_count, semicolon);
8085 arg = skipwhite(arg + 1); // skip white after '['
8086
8087 // the list item is replaced by a number of items
8088 if (GA_GROW_FAILS(stack, var_count - 1))
8089 {
8090 drop_scope(cctx);
8091 return NULL;
8092 }
8093 --stack->ga_len;
8094 for (idx = 0; idx < var_count; ++idx)
8095 {
8096 ((type_T **)stack->ga_data)[stack->ga_len] =
8097 (semicolon && idx == 0) ? vartype : item_type;
8098 ++stack->ga_len;
8099 }
8100 }
8101
8092 for (idx = 0; idx < var_count; ++idx) 8102 for (idx = 0; idx < var_count; ++idx)
8093 { 8103 {
8094 ((type_T **)stack->ga_data)[stack->ga_len] = 8104 assign_dest_T dest = dest_local;
8095 (semicolon && idx == 0) ? vartype : item_type; 8105 int opt_flags = 0;
8096 ++stack->ga_len; 8106 int vimvaridx = -1;
8097 } 8107 type_T *type = &t_any;
8098 } 8108 type_T *lhs_type = &t_any;
8099 8109 where_T where = WHERE_INIT;
8100 for (idx = 0; idx < var_count; ++idx) 8110
8101 { 8111 p = skip_var_one(arg, FALSE);
8102 assign_dest_T dest = dest_local; 8112 varlen = p - arg;
8103 int opt_flags = 0; 8113 name = vim_strnsave(arg, varlen);
8104 int vimvaridx = -1; 8114 if (name == NULL)
8105 type_T *type = &t_any; 8115 goto failed;
8106 type_T *lhs_type = &t_any; 8116 if (*p == ':')
8107 where_T where = WHERE_INIT; 8117 {
8108 8118 p = skipwhite(p + 1);
8109 p = skip_var_one(arg, FALSE); 8119 lhs_type = parse_type(&p, cctx->ctx_type_list, TRUE);
8110 varlen = p - arg; 8120 }
8111 name = vim_strnsave(arg, varlen); 8121
8112 if (name == NULL) 8122 // TODO: script var not supported?
8113 goto failed; 8123 if (get_var_dest(name, &dest, CMD_for, &opt_flags,
8114 if (*p == ':')
8115 {
8116 p = skipwhite(p + 1);
8117 lhs_type = parse_type(&p, cctx->ctx_type_list, TRUE);
8118 }
8119
8120 // TODO: script var not supported?
8121 if (get_var_dest(name, &dest, CMD_for, &opt_flags,
8122 &vimvaridx, &type, cctx) == FAIL) 8124 &vimvaridx, &type, cctx) == FAIL)
8123 goto failed; 8125 goto failed;
8124 if (dest != dest_local) 8126 if (dest != dest_local)
8125 { 8127 {
8126 if (generate_store_var(cctx, dest, opt_flags, vimvaridx, 8128 if (generate_store_var(cctx, dest, opt_flags, vimvaridx,
8127 0, 0, type, name) == FAIL) 8129 0, 0, type, name) == FAIL)
8128 goto failed; 8130 goto failed;
8129 } 8131 }
8130 else if (varlen == 1 && *arg == '_') 8132 else if (varlen == 1 && *arg == '_')
8131 { 8133 {
8132 // Assigning to "_": drop the value. 8134 // Assigning to "_": drop the value.
8133 if (generate_instr_drop(cctx, ISN_DROP, 1) == NULL) 8135 if (generate_instr_drop(cctx, ISN_DROP, 1) == NULL)
8134 goto failed; 8136 goto failed;
8135 } 8137 }
8136 else 8138 else
8137 { 8139 {
8138 if (lookup_local(arg, varlen, NULL, cctx) == OK) 8140 if (lookup_local(arg, varlen, NULL, cctx) == OK)
8139 { 8141 {
8140 semsg(_(e_variable_already_declared), arg); 8142 semsg(_(e_variable_already_declared), arg);
8141 goto failed; 8143 goto failed;
8142 } 8144 }
8143 8145
8144 if (STRNCMP(name, "s:", 2) == 0) 8146 if (STRNCMP(name, "s:", 2) == 0)
8145 { 8147 {
8146 semsg(_(e_cannot_declare_script_variable_in_function), name); 8148 semsg(_(e_cannot_declare_script_variable_in_function), name);
8147 goto failed; 8149 goto failed;
8148 } 8150 }
8149 8151
8150 // Reserve a variable to store "var". 8152 // Reserve a variable to store "var".
8151 where.wt_index = var_list ? idx + 1 : 0; 8153 where.wt_index = var_list ? idx + 1 : 0;
8152 where.wt_variable = TRUE; 8154 where.wt_variable = TRUE;
8153 if (lhs_type == &t_any) 8155 if (lhs_type == &t_any)
8154 lhs_type = item_type; 8156 lhs_type = item_type;
8155 else if (item_type != &t_unknown 8157 else if (item_type != &t_unknown
8156 && (item_type == &t_any 8158 && (item_type == &t_any
8157 ? need_type(item_type, lhs_type, 8159 ? need_type(item_type, lhs_type,
8158 -1, 0, cctx, FALSE, FALSE) 8160 -1, 0, cctx, FALSE, FALSE)
8159 : check_type(lhs_type, item_type, TRUE, where)) 8161 : check_type(lhs_type, item_type, TRUE, where))
8160 == FAIL) 8162 == FAIL)
8161 goto failed; 8163 goto failed;
8162 var_lvar = reserve_local(cctx, arg, varlen, TRUE, lhs_type); 8164 var_lvar = reserve_local(cctx, arg, varlen, TRUE, lhs_type);
8163 if (var_lvar == NULL) 8165 if (var_lvar == NULL)
8164 // out of memory or used as an argument 8166 // out of memory or used as an argument
8165 goto failed; 8167 goto failed;
8166 8168
8167 if (semicolon && idx == var_count - 1) 8169 if (semicolon && idx == var_count - 1)
8168 var_lvar->lv_type = vartype; 8170 var_lvar->lv_type = vartype;
8169 else 8171 else
8170 var_lvar->lv_type = item_type; 8172 var_lvar->lv_type = item_type;
8171 generate_STORE(cctx, ISN_STORE, var_lvar->lv_idx, NULL); 8173 generate_STORE(cctx, ISN_STORE, var_lvar->lv_idx, NULL);
8172 } 8174 }
8173 8175
8174 if (*p == ',' || *p == ';') 8176 if (*p == ',' || *p == ';')
8175 ++p; 8177 ++p;
8176 arg = skipwhite(p); 8178 arg = skipwhite(p);
8177 vim_free(name); 8179 vim_free(name);
8178 } 8180 }
8179 8181
8180 if (cctx->ctx_compile_type == CT_DEBUG) 8182 if (cctx->ctx_compile_type == CT_DEBUG)
8181 { 8183 {
8182 int save_prev_lnum = cctx->ctx_prev_lnum; 8184 int save_prev_lnum = cctx->ctx_prev_lnum;
8183 8185
8184 // Add ISN_DEBUG here, so that the loop variables can be inspected. 8186 // Add ISN_DEBUG here, so that the loop variables can be inspected.
8185 // Use the prev_lnum from the ISN_DEBUG instruction removed above. 8187 // Use the prev_lnum from the ISN_DEBUG instruction removed above.
8186 cctx->ctx_prev_lnum = prev_lnum; 8188 cctx->ctx_prev_lnum = prev_lnum;
8187 generate_instr_debug(cctx); 8189 generate_instr_debug(cctx);
8188 cctx->ctx_prev_lnum = save_prev_lnum; 8190 cctx->ctx_prev_lnum = save_prev_lnum;
8191 }
8189 } 8192 }
8190 8193
8191 return arg_end; 8194 return arg_end;
8192 8195
8193 failed: 8196 failed:
8215 emsg(_(e_for)); 8218 emsg(_(e_for));
8216 return NULL; 8219 return NULL;
8217 } 8220 }
8218 forscope = &scope->se_u.se_for; 8221 forscope = &scope->se_u.se_for;
8219 cctx->ctx_scope = scope->se_outer; 8222 cctx->ctx_scope = scope->se_outer;
8220 unwind_locals(cctx, scope->se_local_count); 8223 if (cctx->ctx_skip != SKIP_YES)
8221 8224 {
8222 // At end of ":for" scope jump back to the FOR instruction. 8225 unwind_locals(cctx, scope->se_local_count);
8223 generate_JUMP(cctx, JUMP_ALWAYS, forscope->fs_top_label); 8226
8224 8227 // At end of ":for" scope jump back to the FOR instruction.
8225 // Fill in the "end" label in the FOR statement so it can jump here. 8228 generate_JUMP(cctx, JUMP_ALWAYS, forscope->fs_top_label);
8226 isn = ((isn_T *)instr->ga_data) + forscope->fs_top_label; 8229
8227 isn->isn_arg.forloop.for_end = instr->ga_len; 8230 // Fill in the "end" label in the FOR statement so it can jump here.
8228 8231 isn = ((isn_T *)instr->ga_data) + forscope->fs_top_label;
8229 // Fill in the "end" label any BREAK statements 8232 isn->isn_arg.forloop.for_end = instr->ga_len;
8230 compile_fill_jump_to_end(&forscope->fs_end_label, instr->ga_len, cctx); 8233
8231 8234 // Fill in the "end" label any BREAK statements
8232 // Below the ":for" scope drop the "expr" list from the stack. 8235 compile_fill_jump_to_end(&forscope->fs_end_label, instr->ga_len, cctx);
8233 if (generate_instr_drop(cctx, ISN_DROP, 1) == NULL) 8236
8234 return NULL; 8237 // Below the ":for" scope drop the "expr" list from the stack.
8238 if (generate_instr_drop(cctx, ISN_DROP, 1) == NULL)
8239 return NULL;
8240 }
8235 8241
8236 vim_free(scope); 8242 vim_free(scope);
8237 8243
8238 return arg; 8244 return arg;
8239 } 8245 }