Repository: neovim/neovim
File: src/nvim/spellfile.c (C)

Code before:

// Initialize 'spellfile' for the current buffer.
static void init_spellfile(void)
{
  char *lend;
  bool aspath = false;
  char *lstart = curbuf->b_s.b_p_spl;

  if (*curwin->w_s->b_p_spl == NUL || GA_EMPTY(&curwin->w_s->b_langp)) {
    return;
  }

  // Find the end of the language name.  Exclude the region.  If there
  // is a path separator remember the start of the tail.
  for (lend = curwin->w_s->b_p_spl; *lend != NUL
       && vim_strchr(",._", (uint8_t)(*lend)) == NULL; lend++) {
    if (vim_ispathsep(*lend)) {
      aspath = true;
      lstart = lend + 1;
    }
  }

  char *buf = xmalloc(MAXPATHL);
  size_t buf_len = MAXPATHL;

  if (!aspath) {
    char *xdg_path = get_xdg_home(kXDGDataHome);
    // if (!xdg_path) {
    //   xfree(buf);
    //   return;
    // }

    xstrlcpy(buf, xdg_path, buf_len);
    xfree(xdg_path);

    // Append "/spell"
    xstrlcat(buf, "/spell", buf_len);

    // Create the directory if needed
    if (os_mkdir_recurse(buf, 0755, &buf, NULL) != 0) {
      xfree(buf);
      return;
    }
  } else {
    if ((size_t)(lend - curbuf->b_s.b_p_spl) >= buf_len) {
      xfree(buf);
      return;
    }
    xmemcpyz(buf, curbuf->b_s.b_p_spl, (size_t)(lend - curbuf->b_s.b_p_spl));
  }


Review comment (security):
asan

```
= ==13704==ERROR: LeakSanitizer: detected memory leaks
= 
= Direct leak of 4096 byte(s) in 1 object(s) allocated from:
=     #0 0x564ea818dd93 in malloc (/home/runner/work/neovim/neovim/build/bin/nvim+0xd03d93) (BuildId: 839761a9c2c58f0050a91741c7578dac1ff5726f)
=     #1 0x564ea8de5e24 in try_malloc /home/runner/work/neovim/neovim/src/nvim/memory.c:98:15
=     #2 0x564ea8de6014 in xmalloc /home/runner/work/neovim/neovim/src/nvim/memory.c:132:15
=     #3 0x564ea9385cf8 in init_spellfile /home/runner/work/neovim/neovim/src/nvim/spellfile.c:5571:15
=     #4 0x564ea9383d39 in spell_add_word /home/runner/work/neovim/neovim/src/nvim/spellfile.c:5419:7
```

Code after:

// Initialize 'spellfile' for the current buffer.
//
// If the location does not exist, create it. Defaults to
// stdpath("data") + "/spell/{spelllang}.{encoding}.add".
static void init_spellfile(void)
{
  char *lend;
  bool aspath = false;
  char *lstart = curbuf->b_s.b_p_spl;

  if (*curwin->w_s->b_p_spl == NUL || GA_EMPTY(&curwin->w_s->b_langp)) {
    return;
  }

  // Find the end of the language name.  Exclude the region.  If there
  // is a path separator remember the start of the tail.
  for (lend = curwin->w_s->b_p_spl; *lend != NUL
       && vim_strchr(",._", (uint8_t)(*lend)) == NULL; lend++) {
    if (vim_ispathsep(*lend)) {
      aspath = true;
      lstart = lend + 1;
    }
  }

  char *buf = xmalloc(MAXPATHL);
  size_t buf_len = MAXPATHL;

  if (!aspath) {
    char *xdg_path = get_xdg_home(kXDGDataHome);
    xstrlcpy(buf, xdg_path, buf_len);
    xfree(xdg_path);

    xstrlcat(buf, "/spell", buf_len);

    char *failed_dir;
    if (os_mkdir_recurse(buf, 0755, &failed_dir, NULL) != 0) {
      xfree(buf);
      xfree(failed_dir);
      return;
    }
  } else {
    if ((size_t)(lend - curbuf->b_s.b_p_spl) >= buf_len) {
      xfree(buf);
      return;
    }
    xmemcpyz(buf, curbuf->b_s.b_p_spl, (size_t)(lend - curbuf->b_s.b_p_spl));
  }

  // Append spelllang
  vim_snprintf(buf + strlen(buf), buf_len - strlen(buf), "/%.*s", (int)(lend - lstart), lstart);