Re: apparent bug about check_free_strict
Toomas Soome <[email protected]> Mon, 18 Nov 2024 15:28:57 +0200
| Newsgroups | org.kernel.vger.smatch |
|---|---|
| Message-ID | <[email protected]> |
> On 18. Nov 2024, at 14:52, Dan Carpenter <[email protected]> = wrote: >=20 > On Mon, Nov 18, 2024 at 01:55:30PM +0200, Toomas Soome wrote: >> hi! >>=20 >> I did enable illumos kernel memory allocation/free checks = (kmem_alloc/kmem_free) and apparently I did find something interesting. >>=20 >> The warning is: >> = /code/illumos-gate/usr/src/tools/proto/root_i386-nd/opt/onbld/bin/i386/sma= tch: ../../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/sma= tch: ../../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/sma= tch: ../../common/os/devcfg.c:8621 e_ddi_retire_device() warn: passing = freed memory =E2=80=98dip' >>=20 >> The code for first error about pdip is: >>=20 >> 8572 pdip =3D 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 =3D 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); >>=20 >> We get this error about pdip with devfs_clean(), but apparently the = =E2=80=98freed >> state is set with ndi_hold_devi(pdip) call; of course the call itself = is not >> the quilty one, but the construct is =E2=80=94 as soon as I either = comment the >> ndi_hold_devi() out *or* if I move it down before devfs_clean(), then >> the error disappears. >>=20 >> Therefore, it appears that code segment such as: >>=20 >> var =3D f(); >> g(var); >>=20 >> is causing state of var to be set =E2=80=98freed=E2=80=99 and = check_free_strict.c is ending up >> spitting out the warning about passing freed memory with next = function call. >>=20 >=20 > I don't see anything in ndi_hold_devi() which would mark "pdip" as = freed. >=20 As I wrote, I do not think it is really about the function itself, it is = about the sequence =E2=80=94 when I moved the ndi_hold_devi() down just = before the =E2=80=98pdip=E2=80=99 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=3D"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. >=20 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/sma= tch --debug=3Dfree -fident -finline -fno-inline-functions -fno-builtin = -fno-asm -fdiagnostics-show-option -nodefaultlibs -D__sun -m64 = -mtune=3Dopteron -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=3Dgnu99 -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=3Dillumos_kernel --disable=3Duninitialized,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=3D0 --disable=3Dindex_overflow = --disable=3Dsigned,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=3Dmax-inline-insns-single=3D450 -fno-shrink-wrap = -mindirect-branch=3Dthunk-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=3Dkernel 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: >=20 > smdb.py return_states ndi_hold_devi | grep -i free > smdb.py return_states is_leaf_node | grep -i free >=20 > 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 >=20 >>=20 >> now the next warning is about code: >>=20 >> 8609 constraint =3D 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 } >>=20 >> 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 = =E2=80=98dip=E2=80=99. >>=20 >=20 > 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. >=20 >> PS: the line number differences with git is because my branch has = other change >> fixing memory leak discovered by smatch:D >=20 > Fantastic. :) >=20 > regards, > dan carpenter >=20