Skip to content

Run static analysis on OCaml C stubs in the CI #6338

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Mar 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .codechecker.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"analyze": [
"--disable=misc-header-include-cycle",
"--disable=clang-diagnostic-unused-parameter"
]
}
96 changes: 96 additions & 0 deletions .github/workflows/codechecker.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
name: Run CodeChecker static analyzer on XAPI's C stubs
permissions: {}

on:
push:
pull_request:
branches:
- master
- 'feature/**'
- '*-lcm'

concurrency: # On new push, cancel old workflows from the same PR, branch or tag:
group: ${{ github.workflow }}-${{github.event_name}}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
staticanalyzer:
name: Static analyzer for OCaml C stubs
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
env:
XAPI_VERSION: "v0.0.0-${{ github.sha }}"

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Restore cache for compile_commands.json
uses: actions/cache/restore@v4
id: cache-cmds
with:
path: compile_commands.json
key: compile_commands.json-v1-${{ hashFiles('**/dune') }}

- name: Setup XenAPI environment
if: steps.cache-cmds.outputs.cache-hit != 'true'
uses: ./.github/workflows/setup-xapi-environment
with:
xapi_version: ${{ env.XAPI_VERSION }}

- name: Install dune-compiledb to generate compile_commands.json
if: steps.cache-cmds.outputs.cache-hit != 'true'
run: |
opam pin add -y ezjsonm https://github.com/mirage/ezjsonm/releases/download/v1.3.0/ezjsonm-1.3.0.tbz
opam pin add -y dune-compiledb https://github.com/edwintorok/dune-compiledb/releases/download/0.6.0/dune-compiledb-0.6.0.tbz

- name: Trim dune cache
if: steps.cache-cmds.outputs.cache-hit != 'true'
run: opam exec -- dune cache trim --size=2GiB

- name: Generate compile_commands.json
if: steps.cache-cmds.outputs.cache-hit != 'true'
run: opam exec -- make compile_commands.json

- name: Save cache for cmds.json
uses: actions/cache/save@v4
with:
path: compile_commands.json
key: ${{ steps.cache-cmds.outputs.cache-primary-key }}

- name: Upload compile commands json
uses: actions/upload-artifact@v4
with:
path: ${{ github.workspace }}/compile_commands.json

- uses: whisperity/codechecker-analysis-action@v1
id: codechecker
with:
ctu: true
logfile: ${{ github.workspace }}/compile_commands.json
analyze-output: "codechecker_results"

- name: Upload CodeChecker report
uses: actions/upload-artifact@v4
with:
name: codechecker_results
path: "${{ steps.codechecker.outputs.result-html-dir }}"

# cppcheck even for other analyzers apparently, this is
# codechecker's output
- name: convert to SARIF
shell: bash
run: report-converter "codechecker_results" --type cppcheck --output codechecker.sarif --export sarif

- name: Upload CodeChecker SARIF report
uses: actions/upload-artifact@v4
with:
name: codechecker_sarif
path: codechecker.sarif

- name: Upload SARIF report
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: codechecker.sarif
13 changes: 12 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ JOBS = $(shell getconf _NPROCESSORS_ONLN)
PROFILE=release
OPTMANDIR ?= $(OPTDIR)/man/man1/

.PHONY: build clean test doc python format install uninstall coverage
.PHONY: build clean test doc python format install uninstall coverage analyze

# if we have XAPI_VERSION set then set it in dune-project so we use that version number instead of the one obtained from git
# this is typically used when we're not building from a git repo
Expand Down Expand Up @@ -196,6 +196,17 @@ uninstall:
dune uninstall $(DUNE_IU_PACKAGES3)
dune uninstall $(DUNE_IU_PACKAGES4)

# An approximation, we actually depend on all dune files recursively
# Also fixup the directory paths to remove _build
# (we must refer to paths that exist in the repository for static analysis results)
compile_commands.json: Makefile dune
mkdir -p _build/
dune rules | dune-compiledb -o _build/
sed -e 's/"directory".*/"directory": ".",/' <_build/$@ >$@

analyze: compile_commands.json Makefile .codechecker.json
CodeChecker check --config .codechecker.json -l compile_commands.json

compile_flags.txt: Makefile
(ocamlc -config-var ocamlc_cflags;\
ocamlc -config-var ocamlc_cppflags;\
Expand Down
4 changes: 2 additions & 2 deletions ocaml/auth/xa_auth.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*/
#ifndef _XA_AUTH_H_
#define _XA_AUTH_H_
#ifndef XA_AUTH_H_
#define XA_AUTH_H_

#define XA_SUCCESS 0
#define XA_ERR_EXTERNAL 1
Expand Down
8 changes: 4 additions & 4 deletions ocaml/libs/log/syslog_stubs.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@
#include <caml/custom.h>
#include <caml/signals.h>

static int __syslog_level_table[] = {
static int syslog_level_table[] = {
LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_ERR, LOG_WARNING,
LOG_NOTICE, LOG_INFO, LOG_DEBUG
};

static int __syslog_facility_table[] = {
static int syslog_facility_table[] = {
LOG_AUTH, LOG_AUTHPRIV, LOG_CRON, LOG_DAEMON, LOG_FTP, LOG_KERN,
LOG_LOCAL0, LOG_LOCAL1, LOG_LOCAL2, LOG_LOCAL3,
LOG_LOCAL4, LOG_LOCAL5, LOG_LOCAL6, LOG_LOCAL7,
Expand Down Expand Up @@ -54,8 +54,8 @@ value stub_syslog(value facility, value level, value msg)
{
CAMLparam3(facility, level, msg);
char *c_msg = strdup(String_val(msg));
int c_facility = __syslog_facility_table[Int_val(facility)]
| __syslog_level_table[Int_val(level)];
int c_facility = syslog_facility_table[Int_val(facility)]
| syslog_level_table[Int_val(level)];

caml_enter_blocking_section();
syslog(c_facility, "%s", c_msg);
Expand Down
3 changes: 2 additions & 1 deletion ocaml/libs/vhd/vhd_format_lwt/blkgetsize64_stubs.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ CAMLprim value stub_blkgetsize64(value filename){
}
#endif
close(fd);
}
} else
size_in_bytes = -1;
caml_leave_blocking_section();
free((void*)filename_c);

Expand Down
4 changes: 3 additions & 1 deletion unixpwd/c/unixpwd.c
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@
*sp;
char buf[BUFLEN];
int tmp;
FILE *tmp_file;
FILE *tmp_file = NULL;
char tmp_name[PATH_MAX];
struct stat statbuf;
int rc;
Expand All @@ -164,6 +164,8 @@
return rc;
}
if (lckpwdf() != 0) {
if (tmp_file)
fclose(tmp_file);
close(tmp);
unlink(tmp_name);
return ENOLCK;
Expand Down
Loading