plougher / squashfs-tools

tools to create and extract Squashfs filesystems

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

use-after-free compiler warning

wychen opened this issue · comments

When compiling using gcc-12 with -O3 flag, it catches the following issue.

mksquashfs.c:1244:57: warning: pointer may be used after 'realloc' [-Wuse-after-free]
 1244 |                 dir->index_count_p = dir->index_count_p - dir->buff + buff;
      |                                      ~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~
mksquashfs.c:1236:24: note: call to 'realloc' here
 1236 |                 buff = realloc(dir->buff, dir->size += SQUASHFS_METADATA_SIZE);
      |                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
mksquashfs.c:1242:66: warning: pointer may be used after 'realloc' [-Wuse-after-free]
 1242 |                         dir->entry_count_p = (dir->entry_count_p - dir->buff +
      |                                               ~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~
mksquashfs.c:1236:24: note: call to 'realloc' here
 1236 |                 buff = realloc(dir->buff, dir->size += SQUASHFS_METADATA_SIZE);
      |                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
mksquashfs.c:1240:34: warning: pointer may be used after 'realloc' [-Wuse-after-free]
 1240 |                 dir->p = (dir->p - dir->buff) + buff;
      |                          ~~~~~~~~^~~~~~~~~~~~
mksquashfs.c:1236:24: note: call to 'realloc' here
 1236 |                 buff = realloc(dir->buff, dir->size += SQUASHFS_METADATA_SIZE);
      |                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

I believe this would lead to "undefined behavior" in the C standard. To make it perfectly valid, we could calculate the offsets like dir->index_count_p - dir->buff before calling realloc(), and add these offsets to buff afterwards.

Completely wrong ...

There are three pointers affected by the realloc - p, entry_count_p and index_count_p. The code recomputes these after the realloc by subtracting the original buffer value (producing a pure offset), and then adding the new buffer value.

                buff = realloc(dir->buff, dir->size += SQUASHFS_METADATA_SIZE);
                if(buff == NULL)
                        MEM_ERROR();

                dir->p = (dir->p - dir->buff) + buff;
                if(dir->entry_count_p) 
                        dir->entry_count_p = (dir->entry_count_p - dir->buff +
                        buff);
                dir->index_count_p = dir->index_count_p - dir->buff + buff;
                dir->buff = buff;

Do not waste my time submitting invalid issues.

I suspect this is a deliberate time waster because I have said NO to your previous issue (#240) and ignored the pull request you sent after I said NO.

If this continues I will ban you from this project and report you to GitHub.

Thanks for responding! First of all, I would like to apologize if my previous issue and pull request caused any troubles. I'm only trying to help improve the project, and I have no intention to waste anyone's time. To be honest, I'm surprised that you'd make the assumption.

The use-after-free issue in the code might not be straightforward at first, and I was confused by this warning as well and suspected it was just a false positive by the overly cautious compiler. Upon further studying, I believe it is a valid concern. Please take a look at another bug report against squashfs-tools at https://bugzilla.redhat.com/show_bug.cgi?id=2053713, and another very similar issue at https://www.reddit.com/r/C_Programming/comments/vffgpo/annoying_useafterfree_warning_with_realloc_in_gcc/.

The tricky part is, even if we don't dereference the pointer, simply using the pointer value to calculate the offset is still undefined behavior. I know this sounds very strange, but it's what the C standard says.

We can avoid the issue like this:

ptrdiff_t p_offset = dir->p - dir->buff;
ptrdiff_t entry_count_p_offset = dir->entry_count_p ? dir->entry_count_p - dir->buff : 0;
ptrdiff_t index_count_p_offset = dir->index_count_p - dir->buff;

buff = realloc(dir->buff, dir->size += SQUASHFS_METADATA_SIZE);
if (buff == NULL)
    MEM_ERROR();

dir->p = buff + p_offset;
if (dir->entry_count_p)
    dir->entry_count_p = buff + entry_count_p_offset;
dir->index_count_p = buff + index_count_p_offset;
dir->buff = buff;

Once again, I apologize if my previous issue report was perceived as a waste of time, and I appreciate your efforts in maintaining this project.

Thanks for responding! First of all, I would like to apologize if my previous issue and pull request caused any troubles. I'm only trying to help improve the project, and I have no intention to waste anyone's time. To be honest, I'm surprised that you'd make the assumption.

I'll apologize here too, I misinterpreted your intent. But I think one thing which comes over badly in your posts is you "try to teach granny how to suck eggs". By all means report an issue but do not turn it into a lecture with examples how to fix it, as that can easily offend.

The issue here is this is new behaviour in gcc-12, and a google shows this has brought up issues in a large number of projects. The C standard and C compilers are constantly tightening the rules on usage and what is considered good programming practice, largely because it allows greater optimisations to be made. I doubt the C code I wrote back in the 1980s will even compile anymore, let alone work because modern day C compilers make optimisations which completely break what was once considered perfectly correct C code.

Thank you for your understanding and for providing your perspective. I was not aware that my earlier communication style could be perceived as lecturing and offending. Your feedback has been a learning opportunity for me. Given the nature of asynchronous communication here, I was optimizing for efficiency by providing more context and speculative discussion points. I'll be more careful about my style.

C compilers and the C standard are indeed constantly evolving, and I understand that updating a project with a long history to keep up can be time-consuming. I don't have the expertise to assess how likely this particular issue would lead to a real bug in some newer compiler versions and flag combinations. However, since we are discussing it, I believe fixing it wouldn't be harmful. If you don't mind, I can make a pull request to address this issue to save you some time.