Powered by Linux
Re: apparent bug about check_free_strict — Semantic Matching Tool

Re: apparent bug about check_free_strict

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




> On 18. Nov 2024, at 14:52, Dan Carpenter <dan.carpenter@xxxxxxxxxx> wrote:
> 
> On Mon, Nov 18, 2024 at 01:55:30PM +0200, Toomas Soome wrote:
>> hi!
>> 
>> I did enable illumos kernel memory allocation/free checks (kmem_alloc/kmem_free) and apparently I did find something interesting.
>> 
>> The warning is:
>> /code/illumos-gate/usr/src/tools/proto/root_i386-nd/opt/onbld/bin/i386/smatch: ../../common/os/devcfg.c:8583 e_ddi_retire_device() warn: passing freed memory 'pdip'
>> /code/illumos-gate/usr/src/tools/proto/root_i386-nd/opt/onbld/bin/i386/smatch: ../../common/os/devcfg.c:8612 e_ddi_retire_device() warn: passing freed memory 'dip'
>> /code/illumos-gate/usr/src/tools/proto/root_i386-nd/opt/onbld/bin/i386/smatch: ../../common/os/devcfg.c:8621 e_ddi_retire_device() warn: passing freed memory ‘dip'
>> 
>> The code for first error about pdip is:
>> 
>>  8572          pdip = ddi_get_parent(dip);
>>  8573          ndi_hold_devi(pdip);
>>  8574     8575          /*
>>  8576           * Run devfs_clean() in case dip has no constraints and is
>>  8577           * not in use, so is retireable but there are dv_nodes holding
>>  8578           * ref-count on the dip. Note that devfs_clean() always returns
>>  8579           * success.
>>  8580           */
>>  8581          devnm = kmem_alloc(MAXNAMELEN + 1, KM_SLEEP);
>>  8582          (void) ddi_deviname(dip, devnm);
>>  8583          (void) devfs_clean(pdip, devnm + 1, DV_CLEAN_FORCE);
>>  8584          kmem_free(devnm, MAXNAMELEN + 1);
>>  8585     8586          ndi_devi_enter(pdip);
>> 
>> We get this error about pdip with devfs_clean(), but apparently the ‘freed
>> state is set with ndi_hold_devi(pdip) call; of course the call itself is not
>> the quilty one, but the construct is — as soon as I either comment the
>> ndi_hold_devi() out *or* if I move it down before devfs_clean(), then
>> the error disappears.
>> 
>> Therefore, it appears that code segment such as:
>> 
>> var = f();
>> g(var);
>> 
>> is causing state of var to be set ‘freed’ and check_free_strict.c is ending up
>> spitting out the warning about passing freed memory with next function call.
>> 
> 
> I don't see anything in ndi_hold_devi() which would mark "pdip" as freed.
> 


As I wrote, I do not think it is really about the function itself, it is about the sequence — when I moved the ndi_hold_devi() down just before the ‘pdip’ was actually called, then this warning did disappear.

> I don't know how to run Smatch on this file...  Could you re-run Smatch with the
> --debug="free" option and save the output to a file?  Maybe send that output
> along with the whole file or run it against the lates git so I can match the
> line numbers up.
> 

I guess it is a bit more complicated because you will also need the illumos specific update to check_free_strict.

The command in usr/src/uts/intel/genunix is run as:

/code/illumos-gate/usr/src/tools/proto/root_i386-nd/opt/onbld/bin/i386/smatch --debug=free -fident -finline -fno-inline-functions -fno-builtin -fno-asm -fdiagnostics-show-option -nodefaultlibs -D__sun -m64 -mtune=opteron -Ui386 -U__i386 -fno-strict-aliasing -fno-unit-at-a-time -fno-optimize-sibling-calls -O2 -D_ASM_INLINES -ffreestanding -mno-red-zone -mno-mmx -mno-sse -msave-args -Wall -Wextra -g -gdwarf-2 -std=gnu99 -msave-args -Werror -Wno-missing-braces -Wno-sign-compare -Wno-unknown-pragmas -Wno-unused-parameter -Wno-missing-field-initializers -Winline -Wno-unused -Wno-empty-body -p=illumos_kernel --disable=uninitialized,check_check_deref -Wno-vla -Wno-one-bit-signed-bitfield -Wno-external-function-has-definition -Wno-old-style-definition -Wno-strict-prototypes --fatal-checks --timeout=0 --disable=index_overflow --disable=signed,all_func_returns -Wno-unused-variable -Wno-unused-value -Wno-unused-function -Wno-parentheses -Wno-maybe-uninitialized -Wno-clobbered -Wno-empty-body -fno-inline-small-functions -fno-inline-functions-called-once -fno-ipa-cp -fno-ipa-icf -fno-clone-functions -fno-reorder-functions -fno-reorder-blocks-and-partition -fno-aggressive-loop-optimizations --param=max-inline-insns-single=450 -fno-shrink-wrap -mindirect-branch=thunk-extern -mindirect-branch-register -fno-asynchronous-unwind-tables -fstack-protector-strong -fno-eliminate-unused-debug-symbols -fno-eliminate-unused-debug-types -D_KERNEL -ffreestanding -D_SYSCALL32 -D_SYSCALL32_IMPL -D_ELF64 -D_DDI_STRICT -Dsun -D__sun -D__SVR4 -DOPTERON_ERRATUM_88 -DOPTERON_ERRATUM_91 -DOPTERON_ERRATUM_93 -DOPTERON_ERRATUM_95 -DOPTERON_ERRATUM_99 -DOPTERON_ERRATUM_100 -DOPTERON_ERRATUM_101 -DOPTERON_ERRATUM_108 -DOPTERON_ERRATUM_109 -DOPTERON_ERRATUM_121 -DOPTERON_ERRATUM_122 -DOPTERON_ERRATUM_123 -DOPTERON_ERRATUM_131 -DOPTERON_WORKAROUND_6336786 -DOPTERON_ERRATUM_147 -DOPTERON_ERRATUM_172 -DOPTERON_ERRATUM_298 -DOPTERON_ERRATUM_721 -I../../intel -nostdinc -I../../common -I/code/illumos-gate/usr/src/common -I/code/illumos-gate/usr/src/uts/common/fs/zfs -I../../i86pc -c -o /tmp/cw.GCaq5P/cwICaO5P.o ../../common/os/devcfg.c -mcmodel=kernel


I did put the samples of files into http://132-104-190-90.sta.estpak.ee/smatch/, I still need to clean up a bit my smatch repo, that will take a bit more time.

thanks,
toomas

> Are you using the cross function DB?  If so then you could do:
> 
> smdb.py return_states ndi_hold_devi | grep -i free
> smdb.py return_states is_leaf_node | grep -i free
> 
> Somewhere there is a function marking code as freed incorrectly.  But there
> the check_free_strict.c file doesn't really have a long list of free functions.
> They're at the top:
> https://github.com/error27/smatch/blob/master/check_free_strict.c#L50
> 
>> 
>> now the next warning is about code:
>> 
>>  8609          constraint = 1; /* assume constraints allow retire */
>>  8610          (void) e_ddi_retire_notify(dip, &constraint);
>>  8611          if (!is_leaf_node(dip)) {
>>  8612                  ndi_devi_enter(dip);
>>  8613                  ddi_walk_devs(ddi_get_child(dip), e_ddi_retire_notify,
>>  8614                      &constraint);
>>  8615                  ndi_devi_exit(dip);
>>  8616          }
>>  8617
>>  8618          /*
>>  8619           * Now finalize the retire
>>  8620           */
>>  8621          (void) e_ddi_retire_finalize(dip, &constraint);
>>  8622          if (!is_leaf_node(dip)) {
>>  8623                  ndi_devi_enter(dip);
>>  8624                  ddi_walk_devs(ddi_get_child(dip), e_ddi_retire_finalize,
>>  8625                      &constraint);
>>  8626                  ndi_devi_exit(dip);
>>  8627          }
>> 
>> Here we do get warning about ndi_devi_enter(), but if I replace dip in is_leaf_node() by NULL, we do not get any more warnings about ‘dip’.
>> 
> 
> There are two reasons why that is.  1)  Smatch thinks is_leaf_node() is freeing
> the parameter.  2)  If you call is_leaf_node(NULL) then it leads to a crash and
> the check_free_strict.c code only tries to warn about use after frees which are
> reachable.
> 
>> PS: the line number differences with git is because my branch has other change
>> fixing memory leak discovered by smatch:D
> 
> Fantastic.  :)
> 
> regards,
> dan carpenter
> 






[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux