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