{"action":"created","issue":{"url":"https://api.github.com/repos/neovim/neovim/issues/731","labels_url":"https://api.github.com/repos/neovim/neovim/issues/731/labels{/name}","comments_url":"https://api.github.com/repos/neovim/neovim/issues/731/comments","events_url":"https://api.github.com/repos/neovim/neovim/issues/731/events","html_url":"https://github.com/neovim/neovim/issues/731","id":33740426,"number":731,"title":"Replace strncpy/vim_strncpy/STRNCPY with strlcpy","user":{"login":"aktau","id":189413,"avatar_url":"https://avatars.githubusercontent.com/u/189413?v=3","gravatar_id":"","url":"https://api.github.com/users/aktau","html_url":"https://github.com/aktau","followers_url":"https://api.github.com/users/aktau/followers","following_url":"https://api.github.com/users/aktau/following{/other_user}","gists_url":"https://api.github.com/users/aktau/gists{/gist_id}","starred_url":"https://api.github.com/users/aktau/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aktau/subscriptions","organizations_url":"https://api.github.com/users/aktau/orgs","repos_url":"https://api.github.com/users/aktau/repos","events_url":"https://api.github.com/users/aktau/events{/privacy}","received_events_url":"https://api.github.com/users/aktau/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/neovim/neovim/labels/entry-level","name":"entry-level","color":"009800"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":17,"created_at":"2014-05-17T21:48:34Z","updated_at":"2015-04-07T11:23:59Z","closed_at":null,"body":"[strncpy](http://man7.org/linux/man-pages/man3/strcpy.3.html) is [seriously awful](http://stackoverflow.com/a/6987247/558819) (also see these two LWN articles [[1](http://lwn.net/Articles/507319/)], [[2](https://lwn.net/Articles/33812/)]). It actually returns a non-NULL terminated string if the source string is too long. As suggested in that SO post, we should replace it point blank with `strlcpy`. Didn't check if it was available everywhere but we could shim it on the platforms that don't provide it. (yes, that might be an #ifdef, but it'd be very localized and we have to do that for (v)snprintf on windows anyway).\r\n\r\nThis seems to be a good newcomer issue. **Bonus points for integrating a clint rule that warns on `strncpy` usage.** @philix do we have a plan for marking newcomer issues?\r\n\r\n**NOTE**: as far as I can see [strndup](http://man7.org/linux/man-pages/man3/strdup.3.html) does not suffer from this problem, so for allocating-and-copying, there's no problem in the vim codebase.\r\n\r\n```bash\r\n➜  src git:(master) ag -i 'strncpy'\r\nnvim/api/vim.c\r\n122:  strncpy(string, dir.data, dir.size);\r\n\r\nnvim/buffer.c\r\n2138:      vim_strncpy(NameBuff, buf_spname(buf), MAXPATHL - 1);\r\n2486:    vim_strncpy(p, buf_spname(curbuf), IOSIZE - (p - buffer) - 1);\r\n2632:        vim_strncpy(buf, (char_u *)_(\"[No Name]\"), SPACE_FOR_FNAME);\r\n2635:        vim_strncpy(buf, p, SPACE_FOR_FNAME);\r\n2667:          vim_strncpy(buf + off, (char_u *)_(\"help\"),\r\n2677:          vim_strncpy(buf + off, p, (size_t)(SPACE_FOR_DIR - off));\r\n2680:          vim_strncpy(buf + off, (char_u *)\"...\",\r\n3084:        vim_strncpy(NameBuff, buf_spname(wp->w_buffer), MAXPATHL - 1);\r\n3528:    vim_strncpy(buf, (char_u *)(above == 0 ? _(\"All\") : _(\"Bot\")),\r\n3531:    vim_strncpy(buf, (char_u *)_(\"Top\"), (size_t)(buflen - 1));\r\n\r\nnvim/edit.c\r\n3802:               * compl_length, so the next STRNCPY always\r\n3804:              STRNCPY(IObuff, ptr, len);\r\n3827:                STRNCPY(IObuff + len, ptr, tmp_ptr - ptr);\r\n\r\nnvim/eval.c\r\n6360:    vim_strncpy(buf, key, len);\r\n19055:  STRNCPY(IObuff + 8, s, IOSIZE - 8);\r\n\r\nnvim/ex_cmds.c\r\n322:    STRNCPY(sortbuf1, ml_get(l1.lnum) + l1.start_col_nr,\r\n325:    STRNCPY(sortbuf2, ml_get(l2.lnum) + l2.start_col_nr,\r\n\r\nnvim/ex_getln.c\r\n3442:      vim_strncpy(retval, fname, len);\r\n3974:    vim_strncpy(buf, s, l);\r\n3977:    vim_strncpy(buf + l, pat, MAXPATHL - 1 - l);\r\n\r\nnvim/file_search.c\r\n321:      vim_strncpy(ff_expand_buffer, rel_fname, len);\r\n1134:    vim_strncpy(ff_expand_buffer, fname, MAXPATHL - 1);\r\n\r\nnvim/api/helpers.c\r\n78:    strncpy(err->msg, msg, sizeof(err->msg));\r\n\r\nnvim/api/helpers.h\r\n11:    strncpy(err->msg, message, sizeof(err->msg));  \\\r\n\r\nnvim/fold.c\r\n1616:      vim_strncpy(newline + line_len, marker, markerlen);\r\n1619:      STRNCPY(newline + line_len + (p - cms), marker, markerlen);\r\n1685:        STRNCPY(newline, line, p - line);\r\n\r\nnvim/getchar.c\r\n284:    vim_strncpy(buf->bh_curr->b_str + len, s, (size_t)slen);\r\n293:    vim_strncpy(p->b_str, s, (size_t)slen);\r\n\r\nnvim/hardcopy.c\r\n1600:  vim_strncpy(resource->name, (char_u *)name, 63);\r\n1819:      vim_strncpy(resource->title, dsc_line.string, dsc_line.len);\r\n1826:      vim_strncpy(resource->version, dsc_line.string, dsc_line.len);\r\n2231:        vim_strncpy((char_u *)prt_cmap,\r\n2241:      vim_strncpy((char_u *)prt_cmap, p_pmcs, sizeof(prt_cmap) - 3);\r\n\r\nnvim/if_cscope.c\r\n334:  vim_strncpy(buf, (char_u *)p, size - 1);\r\n2093:    vim_strncpy(csdir, (char_u *)csinfo[i].fname,\r\n\r\nnvim/fileio.c\r\n2374:  vim_strncpy(header, (char_u *)crypt_magic[use_crypt_method],\r\n\r\nnvim/mark.c\r\n480:      vim_strncpy(NameBuff + len, fm->fname + 2, MAXPATHL - len - 1);\r\n482:      vim_strncpy(NameBuff, fm->fname, MAXPATHL - 1);\r\n\r\nnvim/memline.c\r\n342:  STRNCPY(b0p->b0_version, \"VIM \", 4);\r\n343:  STRNCPY(b0p->b0_version + 4, Version, 6);\r\n856:        vim_strncpy(b0p->b0_fname, buf->b_ffname,\r\n1148:    vim_strncpy(NameBuff, buf_spname(curbuf), MAXPATHL - 1);\r\n3285:  vim_strncpy(tmp, fname, MAXPATHL - 1);\r\n\r\nnvim/message.c\r\n1900:    vim_strncpy(mp->sb_text, *sb_str, s - *sb_str);\r\n\r\nnvim/misc1.c\r\n512:      vim_strncpy(leader, saved_line, lead_len);\r\n2600:        vim_strncpy(msg_buf, (char_u *)_(\"1 more line\"),\r\n2603:        vim_strncpy(msg_buf, (char_u *)_(\"1 line less\"),\r\n3152:    vim_strncpy(name, (char_u *)envname, ENVNAMELEN - 1);\r\n\r\nnvim/misc2.c\r\n824:  vim_strncpy(dir, fname, MAXPATHL - 1);\r\n\r\nnvim/ops.c\r\n2250:      vim_strncpy(ins_text, firstline + bd.textcol, (size_t)ins_len);\r\n\r\nnvim/option.c\r\n3284:      vim_strncpy(IObuff, (char_u *)_(errmsg), IOSIZE - 1);\r\n7632:      vim_strncpy(NameBuff, varp, MAXPATHL - 1);\r\n\r\nnvim/os/env.c\r\n71:    strncpy(hostname, vutsname.nodename, len - 1);\r\n\r\nnvim/os/fs.c\r\n32:    vim_strncpy(buf, (char_u *)uv_strerror(errno), len - 1);\r\n105:    vim_strncpy(buf, (char_u *) path, e - path);\r\n\r\nnvim/os/server.c\r\n81:  strncpy(addr, endpoint, sizeof(addr));\r\n107:  strncpy(ip, addr, addr_len);\r\n179:  strncpy(addr, endpoint, sizeof(addr));\r\n\r\nnvim/os/users.c\r\n61:    vim_strncpy((char_u *)s, (char_u *)pw->pw_name, len - 1);\r\n\r\nnvim/menu.c\r\n910:      vim_strncpy(path_name, arg, after_dot - arg - 1);\r\n1026:        vim_strncpy(tbuffer, menu->en_dname, TBUFFER_LEN - 2);\r\n1028:        vim_strncpy(tbuffer, menu->dname,  TBUFFER_LEN - 2);\r\n\r\nnvim/path.c\r\n410:      STRNCPY(p, path_end, len);\r\n1532:    vim_strncpy(buf, fname, len - 1);\r\n1960:      STRNCPY(relative_directory, fname, p-fname);\r\n\r\nnvim/os_unix.c\r\n414:          vim_strncpy(newname, name, MAXPATHL);\r\n415:          vim_strncpy(newname + (tail - name), (char_u *)dp->d_name,\r\n\r\nnvim/quickfix.c\r\n519:            vim_strncpy(IObuff, p_str, CMDBUFFSIZE - 2);\r\n521:            vim_strncpy(IObuff, p_str, len);\r\n536:          vim_strncpy(IObuff, p_li->li_tv.vval.v_string, len);\r\n544:        vim_strncpy(IObuff, ml_get_buf(buf, buflnum++, FALSE),\r\n644:          vim_strncpy(errmsg, regmatch.startp[i], len);\r\n\r\nnvim/regexp.c\r\n6853:          vim_strncpy(retval, s, len);\r\n6875:          STRNCPY(retval + len, reg_getline_submatch(lnum),\r\n\r\nnvim/ex_docmd.c\r\n3577:        STRNCPY(ptr, program, i);\r\n4245:          vim_strncpy(buff,\r\n6034:        vim_strncpy(IObuff, buf_spname(wp->w_buffer), IOSIZE - 1);\r\n\r\nnvim/spell.c\r\n1472:              vim_strncpy(fword, ptr, endlen[endidxcnt]);\r\n2195:      vim_strncpy(buf +  n, p, maxlen - 1 - n);\r\n2992:    vim_strncpy(buf, word, len);\r\n3288:    vim_strncpy(syl->sy_chars, s, l);\r\n3699:        vim_strncpy(region_cp, p + 1, 2);\r\n3821:        vim_strncpy(lang, path_tail(spf_name), MAXWLEN);\r\n3942:          vim_strncpy(bp + n, p, l);\r\n4847:        vim_strncpy(key, items[1], AH_KEY_LEN - 1);\r\n5420:        vim_strncpy(key, prevp, p - prevp);\r\n5809:      vim_strncpy(key, prevp, p - prevp);\r\n5840:      vim_strncpy(key, prevp, p - prevp);\r\n5935:                vim_strncpy(newword, ae->ae_add, MAXWLEN - 1);\r\n5949:              vim_strncpy(newword, word, MAXWLEN - 1);\r\n6031:              vim_strncpy(pfx_pfxlist, use_pfxlist, use_pfxlen);\r\n7386:  vim_strncpy(fname, wfname, MAXPATHL - 1);\r\n7811:      vim_strncpy(wfname, fnames[0], MAXPATHL - 1);\r\n8173:        vim_strncpy(buf, curbuf->b_s.b_p_spl,\r\n8182:          vim_strncpy(buf, curbuf->b_s.b_p_spl,\r\n8733:      vim_strncpy(wcopy, stp->st_word, MAXWLEN);\r\n8735:        vim_strncpy(wcopy + stp->st_wordlen,\r\n9024:  vim_strncpy(su->su_badword, su->su_badptr, su->su_badlen);\r\n9470:  vim_strncpy(wcopy + l, p, MAXWLEN - l - 1);\r\n9837:          vim_strncpy(preword + sp->ts_prewordlen,\r\n10975:          STRNCPY(kword + kwordlen[depth], fword + fwordidx[depth],\r\n10979:          STRNCPY(kword + kwordlen[depth], uword + uwordidx[depth],\r\n11184:    vim_strncpy(goodword + stp->st_wordlen,\r\n11774:    vim_strncpy(longword, stp[i].st_word, MAXWLEN);\r\n11776:    vim_strncpy(longword + len, su->su_badptr + stp[i].st_orglen,\r\n12047:    vim_strncpy(word, s, MAXWLEN - 1);\r\n13509:            vim_strncpy(prefix + depth, word, MAXWLEN - depth - 1);\r\n13524:              vim_strncpy(prefix + depth, word_up,\r\n\r\nnvim/strings.c\r\n70:  STRNCPY(p, string, len);\r\n342: * Like strncpy(), but always terminate the result with one NUL.\r\n345:void vim_strncpy(char_u *to, char_u *from, size_t len)\r\n347:  STRNCPY(to, from, len);\r\n\r\nnvim/strings.h\r\n17:void vim_strncpy(char_u *to, char_u *from, size_t len);\r\n\r\nnvim/syntax.c\r\n3016:  vim_strncpy(keyword, kwp, kwlen);\r\n5247:      vim_strncpy(name + 1, p, end - p);\r\n7380:  vim_strncpy(name_u, name, 199);\r\n\r\nnvim/regexp_nfa.c\r\n2365:    STRNCPY(save, &p[last], 2);\r\n2366:    STRNCPY(&p[last], \"+-\", 2);\r\n2368:    STRNCPY(&p[last], save, 2);\r\n\r\nnvim/tag.c\r\n702:          vim_strncpy(tag_name, tagp.tagname, len);\r\n709:          vim_strncpy(fname, p, MAXPATHL);\r\n1858:                  vim_strncpy(p, tagp.command + 2, len);\r\n1868:                vim_strncpy(p, tagp.tagname, len);\r\n2092:      vim_strncpy(buf, ((char_u **)(tag_fnames.ga_data))[\r\n2682:    vim_strncpy(retval + (p - tag_fname), fname,\r\n2842:    vim_strncpy(buf, start, len);\r\n\r\nnvim/version.c\r\n865:    vim_strncpy(modby, (char_u *)_(\"Modified by \"), MODBY_LEN - 1);\r\n867:    vim_strncpy(modby + l, (char_u *)MODIFIED_BY, MODBY_LEN - l - 1);\r\n\r\nnvim/screen.c\r\n2043:        STRNCPY(current_ScreenLine, text, len);\r\n2045:        STRNCPY(current_ScreenLine + col, text, len);\r\n4771:          STRNCPY(buf + len, s, l);\r\n5161:  vim_strncpy(buf, p, sizeof(buf) - 1);\r\n7706:    vim_strncpy(NameBuff, buf_spname(buf), MAXPATHL - 1);\r\n\r\nnvim/vim.h\r\n978:#define STRNCPY(d, s, n)    strncpy((char *)(d), (char *)(s), (size_t)(n))\r\n\r\nnvim/search.c\r\n4343:          /* IOSIZE > compl_length, so the STRNCPY works */\r\n4344:          STRNCPY(IObuff, aux, i);\r\n4378:            STRNCPY(IObuff + i, aux, p - aux);\r\n```\r\n\r\n<bountysource-plugin>\r\n\r\n---\r\nWant to back this issue? **[Place a bounty on it!](https://www.bountysource.com/issues/2210451-replace-strncpy-vim_strncpy-strncpy-with-strlcpy?utm_campaign=plugin&utm_content=tracker%2F461131&utm_medium=issues&utm_source=github)** We accept bounties via [Bountysource](https://www.bountysource.com/?utm_campaign=plugin&utm_content=tracker%2F461131&utm_medium=issues&utm_source=github).\r\n</bountysource-plugin>"},"comment":{"url":"https://api.github.com/repos/neovim/neovim/issues/comments/90511602","html_url":"https://github.com/neovim/neovim/issues/731#issuecomment-90511602","issue_url":"https://api.github.com/repos/neovim/neovim/issues/731","id":90511602,"user":{"login":"EJahren","id":233605,"avatar_url":"https://avatars.githubusercontent.com/u/233605?v=3","gravatar_id":"","url":"https://api.github.com/users/EJahren","html_url":"https://github.com/EJahren","followers_url":"https://api.github.com/users/EJahren/followers","following_url":"https://api.github.com/users/EJahren/following{/other_user}","gists_url":"https://api.github.com/users/EJahren/gists{/gist_id}","starred_url":"https://api.github.com/users/EJahren/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/EJahren/subscriptions","organizations_url":"https://api.github.com/users/EJahren/orgs","repos_url":"https://api.github.com/users/EJahren/repos","events_url":"https://api.github.com/users/EJahren/events{/privacy}","received_events_url":"https://api.github.com/users/EJahren/received_events","type":"User","site_admin":false},"created_at":"2015-04-07T11:23:59Z","updated_at":"2015-04-07T11:23:59Z","body":"sds seems lik a reasonable choice, although since the string type is only defined by `typedef char *sds`\r\nyou wont get a compiler warning if you use a regular string as a sds string. Additionally coverety might\r\nget a lot of false negatives and false positives on determining whether a given string is safe to use as a sds string. Is it really that bad to have to grab the \\0 terminated buffer from a struct when you need the c string?"}}