On 1/2/24 17:40, Eelco Chaudron wrote: > > > On 2 Jan 2024, at 17:31, Ilya Maximets wrote: > >> On 1/2/24 17:14, Eelco Chaudron wrote: >>> >>> >>> On 2 Jan 2024, at 16:55, Ilya Maximets wrote: >>> >>>> On 1/2/24 16:19, Eelco Chaudron wrote: >>>>> >>>>> >>>>> On 2 Jan 2024, at 13:43, Ilya Maximets wrote: >>>>> >>>>>> On 12/20/23 16:07, Eelco Chaudron wrote: >>>>>>> >>>>>>> >>>>>>> On 20 Dec 2023, at 11:19, Eelco Chaudron wrote: >>>>>>> >>>>>>>> This patch identifies new static analysis issues during a GitHub action >>>>>>>> run and reports them. The process involves analyzing the changes >>>>>>>> introduced >>>>>>>> in the current commit and comparing them to those in the preceding >>>>>>>> commit. >>>>>>>> >>>>>>>> However, there are two cases when the GitHub push action runner does >>>>>>>> not >>>>>>>> provide enough details to determen the preceding commit. These cases >>>>>>>> are >>>>>>>> a new branch or a forced push. The strategy for these exceptions is to >>>>>>>> select the first commit not done by the current author as the base >>>>>>>> commit. >>>>>>> >>>>>>> Including Aarons comment on v3 into v4. >>>>>>> >>>>>>> +++ As an alternative we can look at the author (go back in time until >>>>>>> +++ we find a different author), so if you’re lucky and it’s one of your >>>>>>> +++ older patches you will be reminded again and again ;) Not sure if >>>>>>> +++ this is easaly possible with a git command, but it might be worth >>>>>>> +++ trying out. >>>>>>> >>>>>>> ++ I did some experiments with the above approach, and it seems to work >>>>>>> ++ in all the use cases. The only problem could be that if you are also >>>>>>> ++ the owner of a previous patch series, it might use a reference branch >>>>>>> ++ too deep. This could potentially show issues not introduced by your >>>>>>> ++ latest patches. But as you are still the author, you should be >>>>>>> ++ “punished” for your earlier mistakes ;) >>>>>>> ++ >>>>>>> ++ I’ll send out a v4, and we can continue the discussion there if >>>>>>> needed :) >>>>>>> >>>>>>> + I'll take a look after Jan 1, but I guess we might be able to check >>>>>>> + against an upstream reference (for example, we can reference towards >>>>>>> the >>>>>>> + 'upstream' repository - such a reference does require some kind of >>>>>>> + history being pulled) which we know should be stable and 'good'. IE: >>>>>>> + the script could add the OVS github remote if it doesn't already >>>>>>> exist. >>>>>>> + I think we could use that to find the common ancestor. But I need to >>>>>>> + dive into this more. >>>>>>> >>>>>>> I guess we can determine the origin branch going back, and then do >>>>>>> something like >>>>>>> `git merge-base upstream/master HEAD` assuming we fetched the upstream >>>>>>> repository. >>>>>> >>>>>> >>>>>> The 'determine the origin branch' is still tricky and requires some >>>>>> guesswork in case of a new branch or a force push. Maybe something >>>>>> like listing all the heads in upstream repo and finding the one that >>>>>> has the closest merge-base may be an option. Then use that merge base >>>>>> as a base commit to compare against. >>>>>> >>>>>> The merge-base with upstream/master will be a branching point for a >>>>>> release branch, and that is way too far. >>>>> >>>>> ACK, I think going back in time till a different author will solve all >>>>> this for now. >>>>> And this will even work in Ilya’s and my force commit workflow. So for >>>>> now I’ll keep >>>>> it as it. >>>> >>>> It will not work in case you're incorporating someone else's patches in >>>> your patch set, unless you're pushing them one by one. Robot will catch >>>> such problems, but people may miss. Same problem if you are accumulating >>>> multiple different patches before batch-applying them. >>> >>> ACK, this is true. But with this patch in place, the robot should have >>> captured this for you ;) >>> And your actual push to the main branch will also fail. Guess the >>> previously suggested patch -1 >>> will have the same problem. >>> >>> Don’t think there will be a ‘full’ solution that will work in all cases >>> 100% of the time. >> >> But why don't you like "closest merge-base against upstream heads" approach? >> It seems less error prone to me. At least I can't right away pinpoint a >> simple scenario where it will do something unexpected, unless the branch is >> completely diverged from anything upstream. > > The issue only exists for new branches and forced commits. So how would we > determine the branch > to use for the ‘git merge-base upstream/<BRANCH> HEAD’? Check if there is a > branch-XX in the > timeline use it, and if not assume master/main? Or is there a smarter way?
Not smarter, but a bit dumber instead. :) I was thinking about something like this: BASE=HEAD~1 # In case no mergeable heads found. MIN_DISTANCE=1000000 for upstream_head in $(git ls-remote --heads upstream | cut -f 1); do CURR_BASE=$(git merge-base ${upstream_head} HEAD) if [ ${CURR_BASE} ]; then DISTANCE=$(git log --oneline ${CURR_BASE}..HEAD | wc -l); echo $(git name-rev --refs='remotes/upstream/*' ${CURR_BASE}) ${DISTANCE} if test ${MIN_DISTANCE} -gt ${DISTANCE}; then BASE=${CURR_BASE} MIN_DISTANCE=${DISTANCE} fi fi done echo $(git name-rev --refs='remotes/upstream/*' ${BASE}) ${MIN_DISTANCE} > > I’m fine with this too, I can do some experimentation… > >>> This approach works for individual developers and the robot. For >>> maintainers, we can push the >>> new branch, and then the actual patches, although making changes in the >>> middle might require >>> deleting the remote branch, re-creating it, and re-apply. Tried this with >>> stgit, and this seems easy. >>> >>> //Eelco >>> >>>>>>> Both solutions will work, and I have no real preference. >>>>>>> >>>>>>> //Eelco >>>>>>> >>>>>>>> An example error output might look like this: >>>>>>>> >>>>>>>> error level: +0 -0 no changes >>>>>>>> warning level: +2 +0 >>>>>>>> New issue "deadcode.DeadStores Value stored to 'remote' is never >>>>>>>> read" (1 occurrence) >>>>>>>> file:///home/runner/work/ovs/ovs/vswitchd/ovs-vswitchd.c:86 >>>>>>>> New issue "unix.Malloc Potential leak of memory pointed to by >>>>>>>> 'remote'" (1 occurrence) >>>>>>>> file:///home/runner/work/ovs/ovs/vswitchd/ovs-vswitchd.c:95 >>>>>>>> note level: +0 -0 no changes >>>>>>>> all levels: +2 +0 >>>>>>>> >>>>>>>> Signed-off-by: Eelco Chaudron <echau...@redhat.com> >>>>>>>> --- >>>>>>>> >>>>>>>> changes in v2: >>>>>>>> - When it's a new branch, it compares it to the HEAD of the default >>>>>>>> branch. >>>>>>>> >>>>>>>> changes in v3: >>>>>>>> - Include the clang version as part of the cache >>>>>>>> - Change the way it looks for the 'default' branch so it will work >>>>>>>> for patch branches. >>>>>>>> - Also compare to the base branch for forced commits. >>>>>>>> >>>>>>>> changes in v4: >>>>>>>> - No longer look for a default branch, but consume all patches >>>>>>>> from the current author. >>>>>>>> >>>>>>>> .ci/linux-build.sh | 29 ++++++++++ >>>>>>>> .github/workflows/build-and-test.yml | 103 >>>>>>>> ++++++++++++++++++++++++++++++++++ >>>>>>>> 2 files changed, 132 insertions(+) >>>>>>>> >>>>>>>> diff --git a/.ci/linux-build.sh b/.ci/linux-build.sh >>>>>>>> index aa2ecc505..fedf1398a 100755 >>>>>>>> --- a/.ci/linux-build.sh >>>>>>>> +++ b/.ci/linux-build.sh >>>>>>>> @@ -49,6 +49,30 @@ function build_ovs() >>>>>>>> make -j4 >>>>>>>> } >>>>>>>> >>>>>>>> +function clang_analyze() >>>>>>>> +{ >>>>>>>> + [ -d "./base-clang-analyzer-results" ] && cache_build=false \ >>>>>>>> + || cache_build=true >>>>>>>> + if [ "$cache_build" = true ]; then >>>>>>>> + # If this is a cache build, proceed to the base branch's >>>>>>>> directory. >>>>>>>> + cd base_ovs_main >>>>>> >>>>>> pushd/popd might be better here. >>>>> >>>>> ACK will do this next revision. >>>>>> >>>>>>>> + fi; >>>>>>>> + >>>>>>>> + configure_ovs $OPTS >>>>>>>> + make clean >>>>>>>> + scan-build -o ./clang-analyzer-results -sarif --use-cc=clang make >>>>>>>> -j4 >>>>>> >>>>>> We have a make target for clang-analyze and it depends on the clean >>>>>> already. >>>>>> Maybe we can extend it to accept custom arguments via env variable and >>>>>> pass >>>>>> the '-sarif' this way? E.g. make clang-analyze >>>>>> SCAN_BUILD_OPTIONS="-sarif". >>>>> >>>>> Let me look into this, as I like the idea. >>>>> >>>>>> Also, -j4 should be changed to ${JOBS} since that patch got merged. >>>>> >>>>> ACK >>>>> >>>>>> And we have CC defined in the job description, so should not use clang >>>>>> directly. >>>>> >>>>> ACK >>>>> >>>>>>>> + >>>>>>>> + if [ "$cache_build" = true ]; then >>>>>>>> + # Move results, so it will be picked up by the cache. >>>>>>>> + mv ./clang-analyzer-results ../base-clang-analyzer-results >>>>>>>> + cd .. >>>>>>>> + else >>>>>>>> + # Only do the compare on the none cache builds. >>>>>>>> + sarif --check note diff ./base-clang-analyzer-results \ >>>>>>>> + ./clang-analyzer-results >>>>>>>> + fi; >>>>>>>> +} >>>>>>>> + >>>>>>>> if [ "$DEB_PACKAGE" ]; then >>>>>>>> ./boot.sh && ./configure --with-dpdk=$DPDK && make debian >>>>>>>> mk-build-deps --install --root-cmd sudo --remove debian/control >>>>>>>> @@ -116,6 +140,11 @@ fi >>>>>>>> >>>>>>>> OPTS="${EXTRA_OPTS} ${OPTS} $*" >>>>>>>> >>>>>>>> +if [ "$CLANG_ANALYZE" ]; then >>>>>>>> + clang_analyze >>>>>>>> + exit 0 >>>>>>>> +fi >>>>>>>> + >>>>>>>> if [ "$TESTSUITE" = 'test' ]; then >>>>>>>> # 'distcheck' will reconfigure with required options. >>>>>>>> # Now we only need to prepare the Makefile without sparse-wrapped >>>>>>>> CC. >>>>>>>> diff --git a/.github/workflows/build-and-test.yml >>>>>>>> b/.github/workflows/build-and-test.yml >>>>>>>> index 09654205e..cb277ff43 100644 >>>>>>>> --- a/.github/workflows/build-and-test.yml >>>>>>>> +++ b/.github/workflows/build-and-test.yml >>>>>>>> @@ -223,6 +223,109 @@ jobs: >>>>>>>> name: logs-linux-${{ join(matrix.*, '-') }} >>>>>>>> path: logs.tgz >>>>>>>> >>>>>>>> + build-clang-analyze: >>>>>>>> + needs: build-dpdk >>>>>>>> + env: >>>>>>>> + dependencies: | >>>>>>>> + automake bc clang-tools libbpf-dev libnuma-dev libpcap-dev \ >>>>>>>> + libunbound-dev libunwind-dev libssl-dev libtool llvm-dev \ >>>>>>>> + python3-unbound >>>>>> >>>>>> Do we need a python3-unbound? >>>>> >>>>> Added it, as I removed the 32-bit conditional install, but can verify if >>>>> it fails without. >>>>> >>>>>>>> + CC: clang >>>>>>>> + DPDK: dpdk >>>>>>>> + CLANG_ANALYZE: true >>>>>>>> + name: clang-analyze >>>>>>>> + runs-on: ubuntu-22.04 >>>>>>>> + timeout-minutes: 30 >>>>>>>> + >>>>>>>> + steps: >>>>>>>> + - name: checkout >>>>>>>> + uses: actions/checkout@v3 >>>>>>>> + with: >>>>>>>> + fetch-depth: 0 >>>>>>>> + >>>>>>>> + - name: get base branch sha >>>>>>>> + id: base_branch >>>>>>>> + env: >>>>>>>> + BASE_SHA: ${{ github.event.pull_request.base.sha }} >>>>>>>> + EVENT_BEFORE: ${{ github.event.before }} >>>>>>>> + FORCED_PUSH: ${{ github.event.forced }} >>>>>>>> + run: | >>>>>>>> + if [ "$GITHUB_EVENT_NAME" = "pull_request" ]; then >>>>>>>> + echo "sha=$BASE_SHA" >> $GITHUB_OUTPUT >>>>>>>> + else >>>>>>>> + if [ "$EVENT_BEFORE" = >>>>>>>> "0000000000000000000000000000000000000000" ] \ >>>>>>>> + || [ "$FORCED_PUSH" = true ]; then >>>>>>>> + echo "sha=$(git log --pretty=format:"%H %ae" | \ >>>>>>>> + grep -m1 -v $(git log -1 >>>>>>>> --pretty=format:"%ae") | \ >>>>>>>> + awk '{print $1}')" >> $GITHUB_OUTPUT >>>>>>>> + else >>>>>>>> + echo "sha=$EVENT_BEFORE" >> $GITHUB_OUTPUT >>>>>>>> + fi >>>>>>>> + fi >>>>>>>> + >>>>>>>> + - name: checkout base branch >>>>>>>> + uses: actions/checkout@v3 >>>>>>>> + with: >>>>>>>> + ref: ${{ steps.base_branch.outputs.sha }} >>>>>>>> + path: base_ovs_main >>>>>>>> + >>>>>>>> + - name: update PATH >>>>>>>> + run: | >>>>>>>> + echo "$HOME/bin" >> $GITHUB_PATH >>>>>>>> + echo "$HOME/.local/bin" >> $GITHUB_PATH >>>>>>>> + >>>>>>>> + - name: generate cache key >>>>>>>> + id: cache_key >>>>>>>> + run: | >>>>>>>> + ver=$(clang -v 2>&1 | grep version | \ >>>>>> >>>>>> s/clang/${CC}/ ? >>>>>> >>>>>> And if we grep for ' version ', the check will work for gcc as well, >>>>>> even if we do not really care about this case. :) >>>>> >>>>> ACK, will make the change below as well. >>>>> >>>>>>>> + sed 's/.*version \([0-9]*\.[0-9]*\.[0-9]*\).*/\1/g') >>>>>>>> + echo "key=clang-${ver}-analyze-$(git -C base_ovs_main >>>>>>>> rev-parse HEAD)" \ >>>>>>>> + >> $GITHUB_OUTPUT >>>>>>>> + >>>>>>>> + - name: check for analyzer result cache >>>>>>>> + id: clang_cache >>>>>>>> + uses: actions/cache@v3 >>>>>>>> + with: >>>>>>>> + path: base-clang-analyzer-results >>>>>>>> + key: ${{ steps.cache_key.outputs.key }} >>>>>>>> + >>>>>>>> + - name: set up python >>>>>>>> + uses: actions/setup-python@v4 >>>>>>>> + with: >>>>>>>> + python-version: '3.9' >>>>>>>> + >>>>>>>> + - name: get cached dpdk-dir >>>>>>>> + uses: actions/cache/restore@v3 >>>>>>>> + with: >>>>>>>> + path: dpdk-dir >>>>>>>> + key: ${{ needs.build-dpdk.outputs.dpdk_key }} >>>>>>>> + >>>>>>>> + - name: update APT cache >>>>>>>> + run: sudo apt update || true >>>>>>>> + >>>>>>>> + - name: install common dependencies >>>>>>>> + run: sudo apt install -y ${{ env.dependencies }} >>>>>>>> + >>>>>>>> + - name: install sarif tools >>>>>>>> + run: sudo pip3 install --disable-pip-version-check sarif-tools >>>>>> >>>>>> '--user' to avoid sudo. Might also be better to add this to the >>>>>> existing command in the linux-prepare script instead to allow pip >>>>>> to choose compatible versions of all the packages. >>>>> >>>>> Let me move it to see if this will work. >>>>> >>>>>>>> + >>>>>>>> + - name: prepare >>>>>>>> + run: ./.ci/linux-prepare.sh >>>>>>>> + >>>>>>>> + - name: build base reference >>>>>>>> + if: steps.clang_cache.outputs.cache-hit != 'true' >>>>>>>> + run: ./.ci/linux-build.sh >>>>>>>> + >>>>>>>> + - name: build >>>>>>>> + run: ./.ci/linux-build.sh >>>>>>>> + >>>>>>>> + - name: save cache >>>>>>>> + uses: actions/cache/save@v3 >>>>>>>> + if: always() && steps.clang_cache.outputs.cache-hit != 'true' >>>>>> >>>>>> So, we will save the cache even if the build of the base reference >>>>>> failed? >>>>>> Maybe move this before the 'build' stage and remove the 'always()' check? >>>>> >>>>> Good catch, will move it up. >>>>> >>>>>>>> + with: >>>>>>>> + path: base-clang-analyzer-results >>>>>>>> + key: ${{ steps.cache_key.outputs.key }} >>>>>>>> + >>>>>>>> build-osx: >>>>>>>> env: >>>>>>>> CC: clang >>>>>>>> >>>>>> >>>>>> Best regards, Ilya Maximets. >>>>> >>>>> Thanks for the comments, will prep a v5. >>>>> >>>>> //Eelco >>>>> >>> > _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev