vim-patch:8.1.0470: pointer ownership around fname_expand() is unclear

Problem:    Pointer ownership around fname_expand() is unclear.
Solution:   Allow b_ffname and b_sfname to point to the same allocated memory,
            only free one.  Update comments.
3d6014f033
This commit is contained in:
Jan Edmund Lazo 2020-12-19 21:58:33 -05:00
parent e465157ecd
commit 7390cc8b29
No known key found for this signature in database
GPG Key ID: 64915E6E9F735B15
4 changed files with 67 additions and 41 deletions

View File

@ -602,8 +602,12 @@ void close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last)
* Remove the buffer from the list. * Remove the buffer from the list.
*/ */
if (wipe_buf) { if (wipe_buf) {
xfree(buf->b_ffname); if (buf->b_sfname != buf->b_ffname) {
xfree(buf->b_sfname); XFREE_CLEAR(buf->b_sfname);
} else {
buf->b_sfname = NULL;
}
XFREE_CLEAR(buf->b_ffname);
if (buf->b_prev == NULL) { if (buf->b_prev == NULL) {
firstbuf = buf->b_next; firstbuf = buf->b_next;
} else { } else {
@ -1693,15 +1697,18 @@ static inline void buf_init_changedtick(buf_T *const buf)
/// if the buffer already exists. /// if the buffer already exists.
/// This is the ONLY way to create a new buffer. /// This is the ONLY way to create a new buffer.
/// ///
/// @param ffname full path of fname or relative /// @param ffname_arg full path of fname or relative
/// @param sfname short fname or NULL /// @param sfname_arg short fname or NULL
/// @param lnum preferred cursor line /// @param lnum preferred cursor line
/// @param flags BLN_ defines /// @param flags BLN_ defines
/// @param bufnr /// @param bufnr
/// ///
/// @return pointer to the buffer /// @return pointer to the buffer
buf_T * buflist_new(char_u *ffname, char_u *sfname, linenr_T lnum, int flags) buf_T *buflist_new(char_u *ffname_arg, char_u *sfname_arg, linenr_T lnum,
int flags)
{ {
char_u *ffname = ffname_arg;
char_u *sfname = sfname_arg;
buf_T *buf; buf_T *buf;
fname_expand(curbuf, &ffname, &sfname); // will allocate ffname fname_expand(curbuf, &ffname, &sfname); // will allocate ffname
@ -1787,8 +1794,12 @@ buf_T * buflist_new(char_u *ffname, char_u *sfname, linenr_T lnum, int flags)
buf->b_wininfo = xcalloc(1, sizeof(wininfo_T)); buf->b_wininfo = xcalloc(1, sizeof(wininfo_T));
if (ffname != NULL && (buf->b_ffname == NULL || buf->b_sfname == NULL)) { if (ffname != NULL && (buf->b_ffname == NULL || buf->b_sfname == NULL)) {
if (buf->b_sfname != buf->b_ffname) {
XFREE_CLEAR(buf->b_sfname);
} else {
buf->b_sfname = NULL;
}
XFREE_CLEAR(buf->b_ffname); XFREE_CLEAR(buf->b_ffname);
XFREE_CLEAR(buf->b_sfname);
if (buf != curbuf) { if (buf != curbuf) {
free_buffer(buf); free_buffer(buf);
} }
@ -2778,28 +2789,32 @@ int buflist_name_nr(int fnum, char_u **fname, linenr_T *lnum)
return OK; return OK;
} }
/* // Set the file name for "buf" to "ffname_arg", short file name to
* Set the file name for "buf"' to 'ffname', short file name to 'sfname'. // "sfname_arg".
* The file name with the full path is also remembered, for when :cd is used. // The file name with the full path is also remembered, for when :cd is used.
* Returns FAIL for failure (file name already in use by other buffer) // Returns FAIL for failure (file name already in use by other buffer)
* OK otherwise. // OK otherwise.
*/ int setfname(
int
setfname(
buf_T *buf, buf_T *buf,
char_u *ffname, char_u *ffname_arg,
char_u *sfname, char_u *sfname_arg,
bool message // give message when buffer already exists bool message // give message when buffer already exists
) )
{ {
char_u *ffname = ffname_arg;
char_u *sfname = sfname_arg;
buf_T *obuf = NULL; buf_T *obuf = NULL;
FileID file_id; FileID file_id;
bool file_id_valid = false; bool file_id_valid = false;
if (ffname == NULL || *ffname == NUL) { if (ffname == NULL || *ffname == NUL) {
// Removing the name. // Removing the name.
if (buf->b_sfname != buf->b_ffname) {
XFREE_CLEAR(buf->b_sfname);
} else {
buf->b_sfname = NULL;
}
XFREE_CLEAR(buf->b_ffname); XFREE_CLEAR(buf->b_ffname);
XFREE_CLEAR(buf->b_sfname);
} else { } else {
fname_expand(buf, &ffname, &sfname); // will allocate ffname fname_expand(buf, &ffname, &sfname); // will allocate ffname
if (ffname == NULL) { // out of memory if (ffname == NULL) { // out of memory
@ -2830,8 +2845,10 @@ setfname(
#ifdef USE_FNAME_CASE #ifdef USE_FNAME_CASE
path_fix_case(sfname); // set correct case for short file name path_fix_case(sfname); // set correct case for short file name
#endif #endif
if (buf->b_sfname != buf->b_ffname) {
xfree(buf->b_sfname);
}
xfree(buf->b_ffname); xfree(buf->b_ffname);
xfree(buf->b_sfname);
buf->b_ffname = ffname; buf->b_ffname = ffname;
buf->b_sfname = sfname; buf->b_sfname = sfname;
} }
@ -2857,7 +2874,9 @@ void buf_set_name(int fnum, char_u *name)
buf = buflist_findnr(fnum); buf = buflist_findnr(fnum);
if (buf != NULL) { if (buf != NULL) {
xfree(buf->b_sfname); if (buf->b_sfname != buf->b_ffname) {
xfree(buf->b_sfname);
}
xfree(buf->b_ffname); xfree(buf->b_ffname);
buf->b_ffname = vim_strsave(name); buf->b_ffname = vim_strsave(name);
buf->b_sfname = NULL; buf->b_sfname = NULL;
@ -4633,16 +4652,18 @@ static bool append_arg_number(win_T *wp, char_u *buf, int buflen, bool add_file)
return true; return true;
} }
/* // Make "*ffname" a full file name, set "*sfname" to "*ffname" if not NULL.
* Make "ffname" a full file name, set "sfname" to "ffname" if not NULL. // "*ffname" becomes a pointer to allocated memory (or NULL).
* "ffname" becomes a pointer to allocated memory (or NULL). // When resolving a link both "*sfname" and "*ffname" will point to the same
*/ // allocated memory.
// The "*ffname" and "*sfname" pointer values on call will not be freed.
// Note that the resulting "*ffname" pointer should be considered not allocaed.
void fname_expand(buf_T *buf, char_u **ffname, char_u **sfname) void fname_expand(buf_T *buf, char_u **ffname, char_u **sfname)
{ {
if (*ffname == NULL) { // if no file name given, nothing to do if (*ffname == NULL) { // no file name given, nothing to do
return; return;
} }
if (*sfname == NULL) { // if no short file name given, use ffname if (*sfname == NULL) { // no short file name given, use ffname
*sfname = *ffname; *sfname = *ffname;
} }
*ffname = (char_u *)fix_fname((char *)(*ffname)); // expand to full path *ffname = (char_u *)fix_fname((char *)(*ffname)); // expand to full path

View File

@ -533,9 +533,11 @@ struct file_buffer {
// b_fname is the same as b_sfname, unless ":cd" has been done, // b_fname is the same as b_sfname, unless ":cd" has been done,
// then it is the same as b_ffname (NULL for no name). // then it is the same as b_ffname (NULL for no name).
// //
char_u *b_ffname; // full path file name char_u *b_ffname; // full path file name, allocated
char_u *b_sfname; // short file name char_u *b_sfname; // short file name, allocated, may be equal to
char_u *b_fname; // current file name // b_ffname
char_u *b_fname; // current file name, points to b_ffname or
// b_sfname
bool file_id_valid; bool file_id_valid;
FileID file_id; FileID file_id;

View File

@ -2066,19 +2066,20 @@ static int check_readonly(int *forceit, buf_T *buf)
return FALSE; return FALSE;
} }
/* // Try to abandon the current file and edit a new or existing file.
* Try to abandon current file and edit a new or existing file. // "fnum" is the number of the file, if zero use "ffname_arg"/"sfname_arg".
* "fnum" is the number of the file, if zero use ffname/sfname. // "lnum" is the line number for the cursor in the new file (if non-zero).
* "lnum" is the line number for the cursor in the new file (if non-zero). //
* // Return:
* Return: // GETFILE_ERROR for "normal" error,
* GETFILE_ERROR for "normal" error, // GETFILE_NOT_WRITTEN for "not written" error,
* GETFILE_NOT_WRITTEN for "not written" error, // GETFILE_SAME_FILE for success
* GETFILE_SAME_FILE for success // GETFILE_OPEN_OTHER for successfully opening another file.
* GETFILE_OPEN_OTHER for successfully opening another file. int getfile(int fnum, char_u *ffname_arg, char_u *sfname_arg, int setpm,
*/ linenr_T lnum, int forceit)
int getfile(int fnum, char_u *ffname, char_u *sfname, int setpm, linenr_T lnum, int forceit)
{ {
char_u *ffname = ffname_arg;
char_u *sfname = sfname_arg;
int other; int other;
int retval; int retval;
char_u *free_me = NULL; char_u *free_me = NULL;

View File

@ -4217,7 +4217,9 @@ void shorten_buf_fname(buf_T *buf, char_u *dirname, int force)
&& (force && (force
|| buf->b_sfname == NULL || buf->b_sfname == NULL
|| path_is_absolute(buf->b_sfname))) { || path_is_absolute(buf->b_sfname))) {
XFREE_CLEAR(buf->b_sfname); if (buf->b_sfname != buf->b_ffname) {
XFREE_CLEAR(buf->b_sfname);
}
p = path_shorten_fname(buf->b_ffname, dirname); p = path_shorten_fname(buf->b_ffname, dirname);
if (p != NULL) { if (p != NULL) {
buf->b_sfname = vim_strsave(p); buf->b_sfname = vim_strsave(p);