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 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.

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.

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