Skip to content

Commit b1ba426

Browse files
authored
chore(ci): Add clang-tidy checks and ensure they pass (#639)
This PR adds a `clang-tidy` check to CI and fixes several issues that it identified (including a few from other repos like ADBC and cudf). A reboot of #538; closes #537.
1 parent e52ff0d commit b1ba426

16 files changed

+201
-25
lines changed

.clang-tidy

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one
2+
# or more contributor license agreements. See the NOTICE file
3+
# distributed with this work for additional information
4+
# regarding copyright ownership. The ASF licenses this file
5+
# to you under the Apache License, Version 2.0 (the
6+
# "License"); you may not use this file except in compliance
7+
# with the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing,
12+
# software distributed under the License is distributed on an
13+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
# KIND, either express or implied. See the License for the
15+
# specific language governing permissions and limitations
16+
# under the License.
17+
---
18+
# Disable valist, it's buggy: https://github.com/llvm/llvm-project/issues/40656
19+
# Disable DeprecatedOrUnsafeBufferHandling because it suggests we replace
20+
# memset and memcpy with memset_s() and memcpy_s() if compiled with C11. Because
21+
# we also support C99, we can't blindly replace those calls.
22+
Checks: '-clang-analyzer-valist.Uninitialized,-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling'
23+
FormatStyle: google

.github/workflows/clang-tidy.yaml

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one
2+
# or more contributor license agreements. See the NOTICE file
3+
# distributed with this work for additional information
4+
# regarding copyright ownership. The ASF licenses this file
5+
# to you under the Apache License, Version 2.0 (the
6+
# "License"); you may not use this file except in compliance
7+
# with the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing,
12+
# software distributed under the License is distributed on an
13+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
# KIND, either express or implied. See the License for the
15+
# specific language governing permissions and limitations
16+
# under the License.
17+
18+
name: clang-tidy
19+
20+
on:
21+
push:
22+
branches:
23+
- main
24+
pull_request:
25+
branches:
26+
- main
27+
paths:
28+
- 'CMakeLists.txt'
29+
- '.github/workflows/clang-tidy.yaml'
30+
- 'src/nanoarrow/**'
31+
32+
permissions:
33+
contents: read
34+
35+
jobs:
36+
clang-tidy:
37+
38+
runs-on: ubuntu-latest
39+
40+
name: ${{ matrix.config.label }}
41+
42+
steps:
43+
- uses: actions/checkout@v4
44+
45+
- name: Cache Arrow C++ Build
46+
id: cache-arrow-build
47+
uses: actions/cache@v4
48+
with:
49+
path: arrow
50+
# Bump the number at the end of this line to force a new Arrow C++ build
51+
key: arrow-${{ runner.os }}-${{ runner.arch }}-1
52+
53+
- name: Build Arrow C++
54+
if: steps.cache-arrow-build.outputs.cache-hit != 'true'
55+
shell: bash
56+
run: |
57+
ci/scripts/build-arrow-cpp-minimal.sh 15.0.2 arrow
58+
59+
- name: Build nanoarrow
60+
run: |
61+
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:`pwd`/dist/lib
62+
sudo ldconfig
63+
64+
ARROW_PATH="$(pwd)/arrow"
65+
mkdir build
66+
cd build
67+
68+
cmake .. -DNANOARROW_DEVICE=ON -DNANOARROW_IPC=ON \
69+
-DNANOARROW_BUILD_TESTS=ON -DCMAKE_POSITION_INDEPENDENT_CODE=ON \
70+
-DCMAKE_BUILD_TYPE=Debug -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
71+
-DCMAKE_PREFIX_PATH="${ARROW_PATH}"
72+
73+
cmake --build .
74+
75+
- name: Run clang-tidy
76+
run: |
77+
ci/scripts/run-clang-tidy.sh . build/

ci/scripts/run-clang-tidy.sh

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#!/usr/bin/env bash
2+
#
3+
# Licensed to the Apache Software Foundation (ASF) under one
4+
# or more contributor license agreements. See the NOTICE file
5+
# distributed with this work for additional information
6+
# regarding copyright ownership. The ASF licenses this file
7+
# to you under the Apache License, Version 2.0 (the
8+
# "License"); you may not use this file except in compliance
9+
# with the License. You may obtain a copy of the License at
10+
#
11+
# http://www.apache.org/licenses/LICENSE-2.0
12+
#
13+
# Unless required by applicable law or agreed to in writing,
14+
# software distributed under the License is distributed on an
15+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16+
# KIND, either express or implied. See the License for the
17+
# specific language governing permissions and limitations
18+
# under the License.
19+
20+
set -e
21+
22+
main() {
23+
local -r source_dir="${1}"
24+
local -r build_dir="${2}"
25+
26+
if [ $(uname) = "Darwin" ]; then
27+
local -r jobs=$(sysctl -n hw.ncpu)
28+
else
29+
local -r jobs=$(nproc)
30+
fi
31+
32+
set -x
33+
34+
run-clang-tidy -p "${build_dir}" -j$jobs \
35+
-extra-arg=-Wno-unknown-warning-option | \
36+
tee "${build_dir}/clang-tidy-output.txt"
37+
38+
if grep -e "warning:" -e "error:" "${build_dir}/clang-tidy-output.txt"; then
39+
echo "Warnings or errors found!"
40+
exit 1
41+
else
42+
echo "No warnings or errors found!"
43+
fi
44+
45+
set +x
46+
}
47+
48+
main "$@"

src/nanoarrow/common/array.c

+3-1
Original file line numberDiff line numberDiff line change
@@ -842,7 +842,9 @@ static int ArrowArrayViewValidateMinimal(struct ArrowArrayView* array_view,
842842
for (int i = 0; i < 2; i++) {
843843
int64_t element_size_bytes = array_view->layout.element_size_bits[i] / 8;
844844
// Initialize with a value that will cause an error if accidentally used uninitialized
845-
int64_t min_buffer_size_bytes = array_view->buffer_views[i].size_bytes + 1;
845+
// Need to suppress the clang-tidy warning because gcc warns for possible use
846+
int64_t min_buffer_size_bytes = // NOLINT(clang-analyzer-deadcode.DeadStores)
847+
array_view->buffer_views[i].size_bytes + 1;
846848

847849
switch (array_view->layout.buffer_type[i]) {
848850
case NANOARROW_BUFFER_TYPE_VALIDITY:

src/nanoarrow/common/inline_buffer.h

+13
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ static inline ArrowErrorCode ArrowBufferReserve(struct ArrowBuffer* buffer,
214214
static inline void ArrowBufferAppendUnsafe(struct ArrowBuffer* buffer, const void* data,
215215
int64_t size_bytes) {
216216
if (size_bytes > 0) {
217+
NANOARROW_DCHECK(buffer->data != NULL);
217218
memcpy(buffer->data + buffer->size_bytes, data, size_bytes);
218219
buffer->size_bytes += size_bytes;
219220
}
@@ -295,8 +296,10 @@ static inline ArrowErrorCode ArrowBufferAppendFill(struct ArrowBuffer* buffer,
295296

296297
NANOARROW_RETURN_NOT_OK(ArrowBufferReserve(buffer, size_bytes));
297298

299+
NANOARROW_DCHECK(buffer->data != NULL); // To help clang-tidy
298300
memset(buffer->data + buffer->size_bytes, value, size_bytes);
299301
buffer->size_bytes += size_bytes;
302+
300303
return NANOARROW_OK;
301304
}
302305

@@ -413,6 +416,8 @@ static inline void ArrowBitsUnpackInt32(const uint8_t* bits, int64_t start_offse
413416
return;
414417
}
415418

419+
NANOARROW_DCHECK(bits != NULL && out != NULL);
420+
416421
const int64_t i_begin = start_offset;
417422
const int64_t i_end = start_offset + length;
418423
const int64_t i_last_valid = i_end - 1;
@@ -461,6 +466,12 @@ static inline void ArrowBitSetTo(uint8_t* bits, int64_t i, uint8_t bit_is_set) {
461466

462467
static inline void ArrowBitsSetTo(uint8_t* bits, int64_t start_offset, int64_t length,
463468
uint8_t bits_are_set) {
469+
if (length == 0) {
470+
return;
471+
}
472+
473+
NANOARROW_DCHECK(bits != NULL);
474+
464475
const int64_t i_begin = start_offset;
465476
const int64_t i_end = start_offset + length;
466477
const uint8_t fill_byte = (uint8_t)(-bits_are_set);
@@ -504,6 +515,8 @@ static inline int64_t ArrowBitCountSet(const uint8_t* bits, int64_t start_offset
504515
return 0;
505516
}
506517

518+
NANOARROW_DCHECK(bits != NULL);
519+
507520
const int64_t i_begin = start_offset;
508521
const int64_t i_end = start_offset + length;
509522
const int64_t i_last_valid = i_end - 1;

src/nanoarrow/common/nanoarrow_hpp_test.cc

+9-8
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ TEST(NanoarrowHppTest, NanoarrowHppUniqueArrayTest) {
5050

5151
// move constructor
5252
nanoarrow::UniqueArray array2 = std::move(array);
53-
EXPECT_EQ(array->release, nullptr);
53+
EXPECT_EQ(array->release, nullptr); // NOLINT(clang-analyzer-cplusplus.Move)
5454
EXPECT_NE(array2->release, nullptr);
5555
EXPECT_EQ(array2->length, 1);
5656

@@ -71,7 +71,7 @@ TEST(NanoarrowHppTest, NanoarrowHppUniqueSchemaTest) {
7171

7272
// move constructor
7373
nanoarrow::UniqueSchema schema2 = std::move(schema);
74-
EXPECT_EQ(schema->release, nullptr);
74+
EXPECT_EQ(schema->release, nullptr); // NOLINT(clang-analyzer-cplusplus.Move)
7575
EXPECT_NE(schema2->release, nullptr);
7676
EXPECT_STREQ(schema2->format, "i");
7777

@@ -101,7 +101,7 @@ TEST(NanoarrowHppTest, NanoarrowHppUniqueArrayStreamTest) {
101101

102102
// move constructor
103103
nanoarrow::UniqueArrayStream array_stream2 = std::move(array_stream);
104-
EXPECT_EQ(array_stream->release, nullptr);
104+
EXPECT_EQ(array_stream->release, nullptr); // NOLINT(clang-analyzer-cplusplus.Move)
105105
EXPECT_NE(array_stream2->release, nullptr);
106106
EXPECT_EQ(ArrowArrayStreamGetSchema(array_stream2.get(), schema.get(), nullptr),
107107
NANOARROW_OK);
@@ -137,8 +137,8 @@ TEST(NanoarrowHppTest, NanoarrowHppUniqueBufferTest) {
137137

138138
// move constructor
139139
nanoarrow::UniqueBuffer buffer2 = std::move(buffer);
140-
EXPECT_EQ(buffer->data, nullptr);
141-
EXPECT_EQ(buffer->size_bytes, 0);
140+
EXPECT_EQ(buffer->data, nullptr); // NOLINT(clang-analyzer-cplusplus.Move)
141+
EXPECT_EQ(buffer->size_bytes, 0); // NOLINT(clang-analyzer-cplusplus.Move)
142142
EXPECT_NE(buffer2->data, nullptr);
143143
EXPECT_EQ(buffer2->size_bytes, 123);
144144

@@ -161,8 +161,8 @@ TEST(NanoarrowHppTest, NanoarrowHppUniqueBitmapTest) {
161161

162162
// move constructor
163163
nanoarrow::UniqueBitmap bitmap2 = std::move(bitmap);
164-
EXPECT_EQ(bitmap->buffer.data, nullptr);
165-
EXPECT_EQ(bitmap->size_bits, 0);
164+
EXPECT_EQ(bitmap->buffer.data, nullptr); // NOLINT(clang-analyzer-cplusplus.Move)
165+
EXPECT_EQ(bitmap->size_bits, 0); // NOLINT(clang-analyzer-cplusplus.Move)
166166
EXPECT_NE(bitmap2->buffer.data, nullptr);
167167
EXPECT_EQ(bitmap2->size_bits, 123);
168168

@@ -250,7 +250,8 @@ TEST(NanoarrowHppTest, NanoarrowHppUniqueArrayViewTest) {
250250

251251
// move constructor
252252
nanoarrow::UniqueArrayView array_view2 = std::move(array_view);
253-
EXPECT_EQ(array_view->storage_type, NANOARROW_TYPE_UNINITIALIZED);
253+
EXPECT_EQ(array_view->storage_type, // NOLINT(clang-analyzer-cplusplus.Move)
254+
NANOARROW_TYPE_UNINITIALIZED);
254255
EXPECT_EQ(array_view2->storage_type, NANOARROW_TYPE_STRUCT);
255256

256257
// pointer constructor

src/nanoarrow/common/schema.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -1346,7 +1346,7 @@ static inline void ArrowToStringLogChars(char** out, int64_t n_chars_last,
13461346
// In the unlikely snprintf() returning a negative value (encoding error),
13471347
// ensure the result won't cause an out-of-bounds access.
13481348
if (n_chars_last < 0) {
1349-
n_chars = 0;
1349+
n_chars_last = 0;
13501350
}
13511351

13521352
*n_chars += n_chars_last;

src/nanoarrow/common/utils.c

+1
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,7 @@ ArrowErrorCode ArrowDecimalSetDigits(struct ArrowDecimal* decimal,
356356
// https://github.com/apache/arrow/blob/cd3321b28b0c9703e5d7105d6146c1270bbadd7f/cpp/src/arrow/util/decimal.cc#L365
357357
ArrowErrorCode ArrowDecimalAppendDigitsToBuffer(const struct ArrowDecimal* decimal,
358358
struct ArrowBuffer* buffer) {
359+
NANOARROW_DCHECK(decimal->n_words == 2 || decimal->n_words == 4);
359360
int is_negative = ArrowDecimalSign(decimal) < 0;
360361

361362
uint64_t words_little_endian[4];

src/nanoarrow/device/device.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -492,7 +492,7 @@ static ArrowErrorCode ArrowDeviceArrayViewEnsureBufferSizesAsync(
492492
NANOARROW_DCHECK(cursor == (buffer.data + buffer.size_bytes));
493493
ArrowBufferReset(&buffer);
494494

495-
return NANOARROW_OK;
495+
return result;
496496
}
497497

498498
ArrowErrorCode ArrowDeviceArrayViewSetArrayAsync(

src/nanoarrow/device/device_hpp_test.cc

+5-4
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ TEST(NanoarrowDeviceHpp, UniqueDeviceArray) {
2727
ASSERT_NE(array->array.release, nullptr);
2828

2929
nanoarrow::device::UniqueDeviceArray array2 = std::move(array);
30-
ASSERT_EQ(array->array.release, nullptr);
30+
ASSERT_EQ(array->array.release, nullptr); // NOLINT(clang-analyzer-cplusplus.Move)
3131
ASSERT_NE(array2->array.release, nullptr);
3232
}
3333

@@ -46,7 +46,7 @@ TEST(NanoarrowDeviceHpp, UniqueDeviceArrayStream) {
4646
ASSERT_NE(stream->release, nullptr);
4747

4848
nanoarrow::device::UniqueDeviceArrayStream stream2 = std::move(stream);
49-
ASSERT_EQ(stream->release, nullptr);
49+
ASSERT_EQ(stream->release, nullptr); // NOLINT(clang-analyzer-cplusplus.Move)
5050
ASSERT_NE(stream2->release, nullptr);
5151
}
5252

@@ -57,7 +57,7 @@ TEST(NanoarrowDeviceHpp, UniqueDevice) {
5757
ArrowDeviceInitCpu(device.get());
5858

5959
nanoarrow::device::UniqueDevice device2 = std::move(device);
60-
ASSERT_EQ(device->release, nullptr);
60+
ASSERT_EQ(device->release, nullptr); // NOLINT(clang-analyzer-cplusplus.Move)
6161
ASSERT_NE(device2->release, nullptr);
6262
}
6363

@@ -71,5 +71,6 @@ TEST(NanoarrowDeviceHpp, UniqueDeviceArrayView) {
7171

7272
nanoarrow::device::UniqueDeviceArrayView array_view2 = std::move(array_view);
7373
ASSERT_EQ(array_view2->array_view.storage_type, NANOARROW_TYPE_INT32);
74-
ASSERT_EQ(array_view->array_view.storage_type, NANOARROW_TYPE_UNINITIALIZED);
74+
ASSERT_EQ(array_view->array_view.storage_type, // NOLINT(clang-analyzer-cplusplus.Move)
75+
NANOARROW_TYPE_UNINITIALIZED);
7576
}

src/nanoarrow/device/metal_test.cc

-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,6 @@ TEST(NanoarrowDeviceMetal, DeviceGpuBufferMove) {
7575
struct ArrowBufferView view = {data, sizeof(data)};
7676

7777
ASSERT_EQ(ArrowDeviceBufferInit(cpu, view, gpu, &buffer), NANOARROW_OK);
78-
auto mtl_buffer = reinterpret_cast<MTL::Buffer*>(buffer.data);
7978

8079
// GPU -> GPU: just a move
8180
uint8_t* old_ptr = buffer.data;

src/nanoarrow/ipc/decoder.c

+4
Original file line numberDiff line numberDiff line change
@@ -1506,6 +1506,9 @@ struct ArrowIpcIntervalMonthDayNano {
15061506
static int ArrowIpcDecoderSwapEndian(struct ArrowIpcBufferSource* src,
15071507
struct ArrowBufferView* out_view,
15081508
struct ArrowBuffer* dst, struct ArrowError* error) {
1509+
NANOARROW_DCHECK(out_view->size_bytes > 0);
1510+
NANOARROW_DCHECK(out_view->data.data != NULL);
1511+
15091512
// Some buffer data types don't need any endian swapping
15101513
switch (src->data_type) {
15111514
case NANOARROW_TYPE_BOOL:
@@ -1539,6 +1542,7 @@ static int ArrowIpcDecoderSwapEndian(struct ArrowIpcBufferSource* src,
15391542
uint64_t* ptr_dst = (uint64_t*)dst->data;
15401543
uint64_t words[4];
15411544
int n_words = (int)(src->element_size_bits / 64);
1545+
NANOARROW_DCHECK(n_words == 2 || n_words == 4);
15421546

15431547
for (int64_t i = 0; i < (dst->size_bytes / n_words / 8); i++) {
15441548
for (int j = 0; j < n_words; j++) {

src/nanoarrow/ipc/ipc_hpp_test.cc

+4-4
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ TEST(NanoarrowIpcHppTest, NanoarrowIpcHppTestUniqueDecoder) {
2828

2929
nanoarrow::ipc::UniqueDecoder decoder2 = std::move(decoder);
3030
EXPECT_NE(decoder2->private_data, nullptr);
31-
EXPECT_EQ(decoder->private_data, nullptr);
31+
EXPECT_EQ(decoder->private_data, nullptr); // NOLINT(clang-analyzer-cplusplus.Move)
3232
}
3333

3434
TEST(NanoarrowIpcHppTest, NanoarrowIpcHppTestUniqueEncoder) {
@@ -40,7 +40,7 @@ TEST(NanoarrowIpcHppTest, NanoarrowIpcHppTestUniqueEncoder) {
4040

4141
nanoarrow::ipc::UniqueEncoder encoder2 = std::move(encoder);
4242
EXPECT_NE(encoder2->private_data, nullptr);
43-
EXPECT_EQ(encoder->private_data, nullptr);
43+
EXPECT_EQ(encoder->private_data, nullptr); // NOLINT(clang-analyzer-cplusplus.Move)
4444
}
4545

4646
TEST(NanoarrowIpcHppTest, NanoarrowIpcHppTestUniqueInputStream) {
@@ -54,7 +54,7 @@ TEST(NanoarrowIpcHppTest, NanoarrowIpcHppTestUniqueInputStream) {
5454

5555
nanoarrow::ipc::UniqueInputStream input2 = std::move(input);
5656
EXPECT_NE(input2->release, nullptr);
57-
EXPECT_EQ(input->release, nullptr);
57+
EXPECT_EQ(input->release, nullptr); // NOLINT(clang-analyzer-cplusplus.Move)
5858
}
5959

6060
TEST(NanoarrowIpcHppTest, NanoarrowIpcHppTestUniqueOutputStream) {
@@ -68,5 +68,5 @@ TEST(NanoarrowIpcHppTest, NanoarrowIpcHppTestUniqueOutputStream) {
6868

6969
nanoarrow::ipc::UniqueOutputStream output2 = std::move(output);
7070
EXPECT_NE(output2->release, nullptr);
71-
EXPECT_EQ(output->release, nullptr);
71+
EXPECT_EQ(output->release, nullptr); // NOLINT(clang-analyzer-cplusplus.Move)
7272
}

0 commit comments

Comments
 (0)