mirror of
				https://github.com/neovim/neovim.git
				synced 2025-11-04 09:44:31 +00:00 
			
		
		
		
	fix(lua): disallow vim.wait() in fast contexts
`vim.wait()` cannot be called in a fast callback since the main loop cannot be run in that context as it is not reentrant Fixes #26122
This commit is contained in:
		
				
					committed by
					
						
						Lewis Russell
					
				
			
			
				
	
			
			
			
						parent
						
							6343d41436
						
					
				
				
					commit
					84bbe4b0ca
				
			@@ -1143,6 +1143,8 @@ vim.wait({time}, {callback}, {interval}, {fast_only})             *vim.wait()*
 | 
			
		||||
    milliseconds (default 200). Nvim still processes other events during this
 | 
			
		||||
    time.
 | 
			
		||||
 | 
			
		||||
    Cannot be called while in an |api-fast| event.
 | 
			
		||||
 | 
			
		||||
    Examples: >lua
 | 
			
		||||
        ---
 | 
			
		||||
        -- Wait for 100 ms, allowing other events to process
 | 
			
		||||
@@ -1173,8 +1175,7 @@ vim.wait({time}, {callback}, {interval}, {fast_only})             *vim.wait()*
 | 
			
		||||
      • {interval}   (integer|nil) (Approximate) number of milliseconds to
 | 
			
		||||
                     wait between polls
 | 
			
		||||
      • {fast_only}  (boolean|nil) If true, only |api-fast| events will be
 | 
			
		||||
                     processed. If called from while in an |api-fast| event,
 | 
			
		||||
                     will automatically be set to `true`.
 | 
			
		||||
                     processed.
 | 
			
		||||
 | 
			
		||||
    Return: ~
 | 
			
		||||
        boolean, nil|-1|-2
 | 
			
		||||
@@ -1828,7 +1829,8 @@ vim.system({cmd}, {opts}, {on_exit})                            *vim.system()*
 | 
			
		||||
        • pid (integer) Process ID
 | 
			
		||||
        • wait (fun(timeout: integer|nil): SystemCompleted) Wait for the
 | 
			
		||||
          process to complete. Upon timeout the process is sent the KILL
 | 
			
		||||
          signal (9) and the exit code is set to 124.
 | 
			
		||||
          signal (9) and the exit code is set to 124. Cannot be called in
 | 
			
		||||
          |api-fast|.
 | 
			
		||||
          • SystemCompleted is an object with the fields:
 | 
			
		||||
            • code: (integer)
 | 
			
		||||
            • signal: (integer)
 | 
			
		||||
 
 | 
			
		||||
@@ -325,6 +325,8 @@ The following changes to existing APIs or features add new behavior.
 | 
			
		||||
  NOTE: the regexp engine still has a hard-coded limit of considering
 | 
			
		||||
  6 composing chars only.
 | 
			
		||||
 | 
			
		||||
• |vim.wait()| is no longer allowed to be called in |api-fast|.
 | 
			
		||||
 | 
			
		||||
==============================================================================
 | 
			
		||||
REMOVED FEATURES                                                 *news-removed*
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -124,7 +124,8 @@ vim.log = {
 | 
			
		||||
--- @return vim.SystemObj Object with the fields:
 | 
			
		||||
---   - pid (integer) Process ID
 | 
			
		||||
---   - wait (fun(timeout: integer|nil): SystemCompleted) Wait for the process to complete. Upon
 | 
			
		||||
---     timeout the process is sent the KILL signal (9) and the exit code is set to 124.
 | 
			
		||||
---     timeout the process is sent the KILL signal (9) and the exit code is set to 124. Cannot
 | 
			
		||||
---     be called in |api-fast|.
 | 
			
		||||
---     - SystemCompleted is an object with the fields:
 | 
			
		||||
---      - code: (integer)
 | 
			
		||||
---      - signal: (integer)
 | 
			
		||||
 
 | 
			
		||||
@@ -205,6 +205,8 @@ function vim.schedule(fn) end
 | 
			
		||||
--- milliseconds (default 200). Nvim still processes other events during
 | 
			
		||||
--- this time.
 | 
			
		||||
---
 | 
			
		||||
--- Cannot be called while in an |api-fast| event.
 | 
			
		||||
---
 | 
			
		||||
--- Examples:
 | 
			
		||||
---
 | 
			
		||||
--- ```lua
 | 
			
		||||
@@ -235,8 +237,6 @@ function vim.schedule(fn) end
 | 
			
		||||
--- @param callback? fun(): boolean Optional callback. Waits until {callback} returns true
 | 
			
		||||
--- @param interval? integer (Approximate) number of milliseconds to wait between polls
 | 
			
		||||
--- @param fast_only? boolean If true, only |api-fast| events will be processed.
 | 
			
		||||
---                           If called from while in an |api-fast| event, will
 | 
			
		||||
---                           automatically be set to `true`.
 | 
			
		||||
--- @return boolean, nil|-1|-2
 | 
			
		||||
---     - If {callback} returns `true` during the {time}: `true, nil`
 | 
			
		||||
---     - If {callback} never returns `true` during the {time}: `false, -1`
 | 
			
		||||
 
 | 
			
		||||
@@ -411,6 +411,10 @@ static bool nlua_wait_condition(lua_State *lstate, int *status, bool *callback_r
 | 
			
		||||
static int nlua_wait(lua_State *lstate)
 | 
			
		||||
  FUNC_ATTR_NONNULL_ALL
 | 
			
		||||
{
 | 
			
		||||
  if (in_fast_callback) {
 | 
			
		||||
    return luaL_error(lstate, e_luv_api_disabled, "vim.wait");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  intptr_t timeout = luaL_checkinteger(lstate, 1);
 | 
			
		||||
  if (timeout < 0) {
 | 
			
		||||
    return luaL_error(lstate, "timeout must be >= 0");
 | 
			
		||||
@@ -449,8 +453,7 @@ static int nlua_wait(lua_State *lstate)
 | 
			
		||||
    fast_only = lua_toboolean(lstate, 4);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  MultiQueue *loop_events = fast_only || in_fast_callback > 0
 | 
			
		||||
                            ? main_loop.fast_events : main_loop.events;
 | 
			
		||||
  MultiQueue *loop_events = fast_only ? main_loop.fast_events : main_loop.events;
 | 
			
		||||
 | 
			
		||||
  TimeWatcher *tw = xmalloc(sizeof(TimeWatcher));
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2769,6 +2769,19 @@ describe('lua stdlib', function()
 | 
			
		||||
        eq({'notification', 'wait', {-2}}, next_msg(500))
 | 
			
		||||
      end)
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    it('should not run in fast callbacks #26122', function()
 | 
			
		||||
      exec_lua([[
 | 
			
		||||
        vim.uv.new_timer():start(0, 100, function()
 | 
			
		||||
          local count = 0
 | 
			
		||||
          vim.wait(100, function()
 | 
			
		||||
            count = count + 1
 | 
			
		||||
            return count == 10
 | 
			
		||||
          end, 100)
 | 
			
		||||
        end)
 | 
			
		||||
      ]])
 | 
			
		||||
      assert_alive()
 | 
			
		||||
    end)
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
  it('vim.notify_once', function()
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user