github-advanced-security[bot] commented on code in PR #15917:
URL: https://github.com/apache/druid/pull/15917#discussion_r1492003925


##########
processing/src/main/java/org/apache/druid/frame/write/columnar/NumericArrayFrameColumnWriter.java:
##########
@@ -0,0 +1,193 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.druid.frame.write.columnar;
+
+import org.apache.datasketches.memory.WritableMemory;
+import org.apache.druid.error.DruidException;
+import org.apache.druid.frame.allocation.AppendableMemory;
+import org.apache.druid.frame.allocation.MemoryAllocator;
+import org.apache.druid.frame.allocation.MemoryRange;
+import org.apache.druid.frame.write.FrameWriterUtils;
+import org.apache.druid.segment.ColumnValueSelector;
+
+import java.util.List;
+
+public abstract class NumericArrayFrameColumnWriter implements 
FrameColumnWriter
+{
+  /**
+   * Equivalent to {@link AppendableMemory#DEFAULT_INITIAL_ALLOCATION_SIZE} / 
3, since the memory would be further split
+   * up into three regions
+   */
+  private static final int INITIAL_ALLOCATION_SIZE = 120;
+
+  public static final byte NULL_ELEMENT_MARKER = 0x00;
+  public static final byte NON_NULL_ELEMENT_MARKER = 0x01;
+
+  /**
+   * A byte required at the beginning for type code
+   */
+  public static final long DATA_OFFSET = 1;
+
+  final ColumnValueSelector selector;
+  final MemoryAllocator allocator;
+  final byte typeCode;
+
+  /**
+   * Row lengths: one int per row with the number of values contained by that 
row and all previous rows.
+   * Only written for multi-value and array columns. When the corresponding 
row is null itself, the length is
+   * written as -(actual length) - 1. (Guaranteed to be a negative number even 
if "actual length" is zero.)
+   */
+  private final AppendableMemory cumulativeRowLengths;
+
+  /**
+   * Denotes if the element of the row is null or not
+   */
+  private final AppendableMemory rowNullityData;
+
+  /**
+   * Row data.
+   */
+  private final AppendableMemory rowData;
+
+  private int lastCumulativeRowLength = 0;
+  private int lastRowLength = -1;
+
+
+  public NumericArrayFrameColumnWriter(
+      final ColumnValueSelector selector,
+      final MemoryAllocator allocator,
+      final byte typeCode
+  )
+  {
+    this.selector = selector;
+    this.allocator = allocator;
+    this.typeCode = typeCode;
+    this.cumulativeRowLengths = AppendableMemory.create(allocator, 
INITIAL_ALLOCATION_SIZE);
+    this.rowNullityData = AppendableMemory.create(allocator, 
INITIAL_ALLOCATION_SIZE);
+    this.rowData = AppendableMemory.create(allocator, INITIAL_ALLOCATION_SIZE);
+  }
+
+  abstract int elementSizeBytes();
+
+  abstract void putNull(WritableMemory memory, long offset);
+
+  abstract void putArrayElement(WritableMemory memory, long offset, Number 
element);
+
+  @Override
+  public boolean addSelection()
+  {
+    List<? extends Number> numericArray = 
FrameWriterUtils.getNumericArrayFromObject(selector.getObject());
+    int rowLength = numericArray == null ? 0 : numericArray.size();
+
+    if ((long) lastCumulativeRowLength + rowLength > Integer.MAX_VALUE) {
+      return false;
+    }
+
+    if (!cumulativeRowLengths.reserveAdditional(Integer.BYTES)) {
+      return false;
+    }
+
+    if (!rowNullityData.reserveAdditional(rowLength * Byte.BYTES)) {
+      return false;
+    }
+
+    if (!rowData.reserveAdditional(rowLength * elementSizeBytes())) {
+      return false;
+    }
+
+    final MemoryRange<WritableMemory> rowLengthsCursor = 
cumulativeRowLengths.cursor();
+
+    if (numericArray == null) {
+      rowLengthsCursor.memory().putInt(rowLengthsCursor.start(), 
-(lastCumulativeRowLength + rowLength) - 1);
+    } else {
+      rowLengthsCursor.memory().putInt(rowLengthsCursor.start(), 
lastCumulativeRowLength + rowLength);
+    }
+    cumulativeRowLengths.advanceCursor(Integer.BYTES);
+    lastRowLength = rowLength;
+    lastCumulativeRowLength += rowLength;
+
+    final MemoryRange<WritableMemory> rowNullityDataCursor = rowLength > 0 ? 
rowNullityData.cursor() : null;
+    final MemoryRange<WritableMemory> rowDataCursor = rowLength > 0 ? 
rowData.cursor() : null;
+
+    for (int i = 0; i < rowLength; ++i) {
+      final Number element = numericArray.get(i);
+      final long memoryOffset = rowDataCursor.start() + ((long) 
elementSizeBytes() * i);

Review Comment:
   ## Dereferenced variable may be null
   
   Variable [rowDataCursor](1) may be null at this access because of [this](2) 
assignment.
   
   [Show more 
details](https://github.com/apache/druid/security/code-scanning/6580)



##########
processing/src/main/java/org/apache/druid/frame/read/columnar/LongArrayFrameColumnReader.java:
##########
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.druid.frame.read.columnar;
+
+import org.apache.datasketches.memory.Memory;
+import org.apache.druid.frame.Frame;
+import org.apache.druid.frame.write.columnar.FrameColumnWriters;
+import org.apache.druid.segment.column.ColumnType;
+
+public class LongArrayFrameColumnReader extends NumericArrayFrameColumnReader
+{
+  public LongArrayFrameColumnReader(int columnNumber)
+  {
+    super(FrameColumnWriters.TYPE_LONG_ARRAY, ColumnType.LONG_ARRAY, 
columnNumber);
+  }
+
+  @Override
+  NumericArrayFrameColumn column(Frame frame, Memory memory, ColumnType 
columnType)
+  {
+    return new LongArrayFrameColumn(frame, memory, columnType);
+  }
+
+  private static class LongArrayFrameColumn extends NumericArrayFrameColumn
+  {
+    public LongArrayFrameColumn(
+        Frame frame,
+        Memory memory,
+        ColumnType columnType
+    )
+    {
+      super(frame, memory, columnType);
+    }
+
+    @Override
+    Number getElement(Memory memory, long rowDataOffset, int cumulativeIndex)
+    {
+      return memory.getLong(rowDataOffset + (long) cumulativeIndex * 
Long.BYTES);

Review Comment:
   ## User-controlled data in arithmetic expression
   
   This arithmetic expression depends on a [user-provided value](1), 
potentially causing an overflow.
   This arithmetic expression depends on a [user-provided value](2), 
potentially causing an overflow.
   
   [Show more 
details](https://github.com/apache/druid/security/code-scanning/6586)



##########
processing/src/main/java/org/apache/druid/frame/read/columnar/DoubleArrayFrameColumnReader.java:
##########
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.druid.frame.read.columnar;
+
+import org.apache.datasketches.memory.Memory;
+import org.apache.druid.frame.Frame;
+import org.apache.druid.frame.write.columnar.FrameColumnWriters;
+import org.apache.druid.segment.column.ColumnType;
+
+public class DoubleArrayFrameColumnReader extends NumericArrayFrameColumnReader
+{
+  public DoubleArrayFrameColumnReader(int columnNumber)
+  {
+    super(FrameColumnWriters.TYPE_DOUBLE_ARRAY, ColumnType.DOUBLE_ARRAY, 
columnNumber);
+  }
+
+  @Override
+  NumericArrayFrameColumn column(Frame frame, Memory memory, ColumnType 
columnType)
+  {
+    return new DoubleArrayFrameColumn(frame, memory, columnType);
+  }
+
+  private static class DoubleArrayFrameColumn extends NumericArrayFrameColumn
+  {
+    public DoubleArrayFrameColumn(
+        Frame frame,
+        Memory memory,
+        ColumnType columnType
+    )
+    {
+      super(frame, memory, columnType);
+    }
+
+    @Override
+    Number getElement(Memory memory, long rowDataOffset, int cumulativeIndex)
+    {
+      return memory.getDouble(rowDataOffset + (long) cumulativeIndex * 
Double.BYTES);

Review Comment:
   ## User-controlled data in arithmetic expression
   
   This arithmetic expression depends on a [user-provided value](1), 
potentially causing an overflow.
   This arithmetic expression depends on a [user-provided value](2), 
potentially causing an overflow.
   
   [Show more 
details](https://github.com/apache/druid/security/code-scanning/6584)



##########
processing/src/main/java/org/apache/druid/frame/write/columnar/NumericArrayFrameColumnWriter.java:
##########
@@ -0,0 +1,193 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.druid.frame.write.columnar;
+
+import org.apache.datasketches.memory.WritableMemory;
+import org.apache.druid.error.DruidException;
+import org.apache.druid.frame.allocation.AppendableMemory;
+import org.apache.druid.frame.allocation.MemoryAllocator;
+import org.apache.druid.frame.allocation.MemoryRange;
+import org.apache.druid.frame.write.FrameWriterUtils;
+import org.apache.druid.segment.ColumnValueSelector;
+
+import java.util.List;
+
+public abstract class NumericArrayFrameColumnWriter implements 
FrameColumnWriter
+{
+  /**
+   * Equivalent to {@link AppendableMemory#DEFAULT_INITIAL_ALLOCATION_SIZE} / 
3, since the memory would be further split
+   * up into three regions
+   */
+  private static final int INITIAL_ALLOCATION_SIZE = 120;
+
+  public static final byte NULL_ELEMENT_MARKER = 0x00;
+  public static final byte NON_NULL_ELEMENT_MARKER = 0x01;
+
+  /**
+   * A byte required at the beginning for type code
+   */
+  public static final long DATA_OFFSET = 1;
+
+  final ColumnValueSelector selector;
+  final MemoryAllocator allocator;
+  final byte typeCode;
+
+  /**
+   * Row lengths: one int per row with the number of values contained by that 
row and all previous rows.
+   * Only written for multi-value and array columns. When the corresponding 
row is null itself, the length is
+   * written as -(actual length) - 1. (Guaranteed to be a negative number even 
if "actual length" is zero.)
+   */
+  private final AppendableMemory cumulativeRowLengths;
+
+  /**
+   * Denotes if the element of the row is null or not
+   */
+  private final AppendableMemory rowNullityData;
+
+  /**
+   * Row data.
+   */
+  private final AppendableMemory rowData;
+
+  private int lastCumulativeRowLength = 0;
+  private int lastRowLength = -1;
+
+
+  public NumericArrayFrameColumnWriter(
+      final ColumnValueSelector selector,
+      final MemoryAllocator allocator,
+      final byte typeCode
+  )
+  {
+    this.selector = selector;
+    this.allocator = allocator;
+    this.typeCode = typeCode;
+    this.cumulativeRowLengths = AppendableMemory.create(allocator, 
INITIAL_ALLOCATION_SIZE);
+    this.rowNullityData = AppendableMemory.create(allocator, 
INITIAL_ALLOCATION_SIZE);
+    this.rowData = AppendableMemory.create(allocator, INITIAL_ALLOCATION_SIZE);
+  }
+
+  abstract int elementSizeBytes();
+
+  abstract void putNull(WritableMemory memory, long offset);
+
+  abstract void putArrayElement(WritableMemory memory, long offset, Number 
element);
+
+  @Override
+  public boolean addSelection()
+  {
+    List<? extends Number> numericArray = 
FrameWriterUtils.getNumericArrayFromObject(selector.getObject());
+    int rowLength = numericArray == null ? 0 : numericArray.size();
+
+    if ((long) lastCumulativeRowLength + rowLength > Integer.MAX_VALUE) {
+      return false;
+    }
+
+    if (!cumulativeRowLengths.reserveAdditional(Integer.BYTES)) {
+      return false;
+    }
+
+    if (!rowNullityData.reserveAdditional(rowLength * Byte.BYTES)) {
+      return false;
+    }
+
+    if (!rowData.reserveAdditional(rowLength * elementSizeBytes())) {
+      return false;
+    }
+
+    final MemoryRange<WritableMemory> rowLengthsCursor = 
cumulativeRowLengths.cursor();
+
+    if (numericArray == null) {
+      rowLengthsCursor.memory().putInt(rowLengthsCursor.start(), 
-(lastCumulativeRowLength + rowLength) - 1);
+    } else {
+      rowLengthsCursor.memory().putInt(rowLengthsCursor.start(), 
lastCumulativeRowLength + rowLength);
+    }
+    cumulativeRowLengths.advanceCursor(Integer.BYTES);
+    lastRowLength = rowLength;
+    lastCumulativeRowLength += rowLength;
+
+    final MemoryRange<WritableMemory> rowNullityDataCursor = rowLength > 0 ? 
rowNullityData.cursor() : null;
+    final MemoryRange<WritableMemory> rowDataCursor = rowLength > 0 ? 
rowData.cursor() : null;
+
+    for (int i = 0; i < rowLength; ++i) {
+      final Number element = numericArray.get(i);
+      final long memoryOffset = rowDataCursor.start() + ((long) 
elementSizeBytes() * i);
+      if (element == null) {
+        rowNullityDataCursor.memory().putByte(rowNullityDataCursor.start() + 
Byte.BYTES * i, NULL_ELEMENT_MARKER);

Review Comment:
   ## Dereferenced variable may be null
   
   Variable [rowNullityDataCursor](1) may be null at this access because of 
[this](2) assignment.
   
   [Show more 
details](https://github.com/apache/druid/security/code-scanning/6581)



##########
processing/src/main/java/org/apache/druid/frame/read/columnar/NumericArrayFrameColumnReader.java:
##########
@@ -0,0 +1,313 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.druid.frame.read.columnar;
+
+import it.unimi.dsi.fastutil.objects.ObjectArrays;
+import org.apache.datasketches.memory.Memory;
+import org.apache.druid.error.DruidException;
+import org.apache.druid.frame.Frame;
+import org.apache.druid.frame.write.columnar.NumericArrayFrameColumnWriter;
+import org.apache.druid.query.monomorphicprocessing.RuntimeShapeInspector;
+import org.apache.druid.query.rowsandcols.column.Column;
+import org.apache.druid.query.rowsandcols.column.ColumnAccessorBasedColumn;
+import 
org.apache.druid.query.rowsandcols.column.accessor.ObjectColumnAccessorBase;
+import org.apache.druid.segment.ColumnValueSelector;
+import org.apache.druid.segment.ObjectColumnSelector;
+import org.apache.druid.segment.column.BaseColumn;
+import org.apache.druid.segment.column.ColumnCapabilitiesImpl;
+import org.apache.druid.segment.column.ColumnType;
+import org.apache.druid.segment.data.ReadableOffset;
+import org.apache.druid.segment.vector.ReadableVectorInspector;
+import org.apache.druid.segment.vector.ReadableVectorOffset;
+import org.apache.druid.segment.vector.VectorObjectSelector;
+
+import javax.annotation.Nullable;
+import java.io.IOException;
+import java.util.Comparator;
+
+public abstract class NumericArrayFrameColumnReader implements 
FrameColumnReader
+{
+  private final byte typeCode;
+  private final ColumnType columnType;
+  private final int columnNumber;
+
+  public NumericArrayFrameColumnReader(byte typeCode, ColumnType columnType, 
int columnNumber)
+  {
+    this.typeCode = typeCode;
+    this.columnType = columnType;
+    this.columnNumber = columnNumber;
+  }
+
+  @Override
+  public Column readRACColumn(Frame frame)
+  {
+    final Memory memory = frame.region(columnNumber);
+    validate(memory);
+    return new ColumnAccessorBasedColumn(column(frame, memory, columnType));
+  }
+
+  @Override
+  public ColumnPlus readColumn(Frame frame)
+  {
+    final Memory memory = frame.region(columnNumber);
+    validate(memory);
+    return new ColumnPlus(
+        column(frame, memory, columnType),
+        ColumnCapabilitiesImpl.createSimpleArrayColumnCapabilities(columnType),
+        frame.numRows()
+    );
+  }
+
+  abstract NumericArrayFrameColumn column(Frame frame, Memory memory, 
ColumnType columnType);
+
+  private void validate(final Memory region)
+  {
+    if (region.getCapacity() < NumericArrayFrameColumnWriter.DATA_OFFSET) {
+      throw DruidException.defensive("Column[%s] is not big enough for a 
header", columnNumber);
+    }
+    final byte typeCode = region.getByte(0);

Review Comment:
   ## Possible confusion of local and field
   
   Potentially confusing name: method [validate](1) also refers to field 
[typeCode](2) (as this.typeCode).
   
   [Show more 
details](https://github.com/apache/druid/security/code-scanning/6583)



##########
processing/src/main/java/org/apache/druid/frame/write/columnar/NumericArrayFrameColumnWriter.java:
##########
@@ -0,0 +1,193 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.druid.frame.write.columnar;
+
+import org.apache.datasketches.memory.WritableMemory;
+import org.apache.druid.error.DruidException;
+import org.apache.druid.frame.allocation.AppendableMemory;
+import org.apache.druid.frame.allocation.MemoryAllocator;
+import org.apache.druid.frame.allocation.MemoryRange;
+import org.apache.druid.frame.write.FrameWriterUtils;
+import org.apache.druid.segment.ColumnValueSelector;
+
+import java.util.List;
+
+public abstract class NumericArrayFrameColumnWriter implements 
FrameColumnWriter
+{
+  /**
+   * Equivalent to {@link AppendableMemory#DEFAULT_INITIAL_ALLOCATION_SIZE} / 
3, since the memory would be further split
+   * up into three regions
+   */
+  private static final int INITIAL_ALLOCATION_SIZE = 120;
+
+  public static final byte NULL_ELEMENT_MARKER = 0x00;
+  public static final byte NON_NULL_ELEMENT_MARKER = 0x01;
+
+  /**
+   * A byte required at the beginning for type code
+   */
+  public static final long DATA_OFFSET = 1;
+
+  final ColumnValueSelector selector;
+  final MemoryAllocator allocator;
+  final byte typeCode;
+
+  /**
+   * Row lengths: one int per row with the number of values contained by that 
row and all previous rows.
+   * Only written for multi-value and array columns. When the corresponding 
row is null itself, the length is
+   * written as -(actual length) - 1. (Guaranteed to be a negative number even 
if "actual length" is zero.)
+   */
+  private final AppendableMemory cumulativeRowLengths;
+
+  /**
+   * Denotes if the element of the row is null or not
+   */
+  private final AppendableMemory rowNullityData;
+
+  /**
+   * Row data.
+   */
+  private final AppendableMemory rowData;
+
+  private int lastCumulativeRowLength = 0;
+  private int lastRowLength = -1;
+
+
+  public NumericArrayFrameColumnWriter(
+      final ColumnValueSelector selector,
+      final MemoryAllocator allocator,
+      final byte typeCode
+  )
+  {
+    this.selector = selector;
+    this.allocator = allocator;
+    this.typeCode = typeCode;
+    this.cumulativeRowLengths = AppendableMemory.create(allocator, 
INITIAL_ALLOCATION_SIZE);
+    this.rowNullityData = AppendableMemory.create(allocator, 
INITIAL_ALLOCATION_SIZE);
+    this.rowData = AppendableMemory.create(allocator, INITIAL_ALLOCATION_SIZE);
+  }
+
+  abstract int elementSizeBytes();
+
+  abstract void putNull(WritableMemory memory, long offset);
+
+  abstract void putArrayElement(WritableMemory memory, long offset, Number 
element);
+
+  @Override
+  public boolean addSelection()
+  {
+    List<? extends Number> numericArray = 
FrameWriterUtils.getNumericArrayFromObject(selector.getObject());
+    int rowLength = numericArray == null ? 0 : numericArray.size();
+
+    if ((long) lastCumulativeRowLength + rowLength > Integer.MAX_VALUE) {
+      return false;
+    }
+
+    if (!cumulativeRowLengths.reserveAdditional(Integer.BYTES)) {
+      return false;
+    }
+
+    if (!rowNullityData.reserveAdditional(rowLength * Byte.BYTES)) {
+      return false;
+    }
+
+    if (!rowData.reserveAdditional(rowLength * elementSizeBytes())) {
+      return false;
+    }
+
+    final MemoryRange<WritableMemory> rowLengthsCursor = 
cumulativeRowLengths.cursor();
+
+    if (numericArray == null) {
+      rowLengthsCursor.memory().putInt(rowLengthsCursor.start(), 
-(lastCumulativeRowLength + rowLength) - 1);
+    } else {
+      rowLengthsCursor.memory().putInt(rowLengthsCursor.start(), 
lastCumulativeRowLength + rowLength);
+    }
+    cumulativeRowLengths.advanceCursor(Integer.BYTES);
+    lastRowLength = rowLength;
+    lastCumulativeRowLength += rowLength;
+
+    final MemoryRange<WritableMemory> rowNullityDataCursor = rowLength > 0 ? 
rowNullityData.cursor() : null;
+    final MemoryRange<WritableMemory> rowDataCursor = rowLength > 0 ? 
rowData.cursor() : null;
+
+    for (int i = 0; i < rowLength; ++i) {
+      final Number element = numericArray.get(i);
+      final long memoryOffset = rowDataCursor.start() + ((long) 
elementSizeBytes() * i);
+      if (element == null) {
+        rowNullityDataCursor.memory().putByte(rowNullityDataCursor.start() + 
Byte.BYTES * i, NULL_ELEMENT_MARKER);

Review Comment:
   ## Result of multiplication cast to wider type
   
   Potential overflow in [int multiplication](1) before it is converted to long 
by use in a numeric context.
   
   [Show more 
details](https://github.com/apache/druid/security/code-scanning/6578)



##########
processing/src/main/java/org/apache/druid/frame/read/columnar/NumericArrayFrameColumnReader.java:
##########
@@ -0,0 +1,313 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.druid.frame.read.columnar;
+
+import it.unimi.dsi.fastutil.objects.ObjectArrays;
+import org.apache.datasketches.memory.Memory;
+import org.apache.druid.error.DruidException;
+import org.apache.druid.frame.Frame;
+import org.apache.druid.frame.write.columnar.NumericArrayFrameColumnWriter;
+import org.apache.druid.query.monomorphicprocessing.RuntimeShapeInspector;
+import org.apache.druid.query.rowsandcols.column.Column;
+import org.apache.druid.query.rowsandcols.column.ColumnAccessorBasedColumn;
+import 
org.apache.druid.query.rowsandcols.column.accessor.ObjectColumnAccessorBase;
+import org.apache.druid.segment.ColumnValueSelector;
+import org.apache.druid.segment.ObjectColumnSelector;
+import org.apache.druid.segment.column.BaseColumn;
+import org.apache.druid.segment.column.ColumnCapabilitiesImpl;
+import org.apache.druid.segment.column.ColumnType;
+import org.apache.druid.segment.data.ReadableOffset;
+import org.apache.druid.segment.vector.ReadableVectorInspector;
+import org.apache.druid.segment.vector.ReadableVectorOffset;
+import org.apache.druid.segment.vector.VectorObjectSelector;
+
+import javax.annotation.Nullable;
+import java.io.IOException;
+import java.util.Comparator;
+
+public abstract class NumericArrayFrameColumnReader implements 
FrameColumnReader
+{
+  private final byte typeCode;
+  private final ColumnType columnType;
+  private final int columnNumber;
+
+  public NumericArrayFrameColumnReader(byte typeCode, ColumnType columnType, 
int columnNumber)
+  {
+    this.typeCode = typeCode;
+    this.columnType = columnType;
+    this.columnNumber = columnNumber;
+  }
+
+  @Override
+  public Column readRACColumn(Frame frame)
+  {
+    final Memory memory = frame.region(columnNumber);
+    validate(memory);
+    return new ColumnAccessorBasedColumn(column(frame, memory, columnType));
+  }
+
+  @Override
+  public ColumnPlus readColumn(Frame frame)
+  {
+    final Memory memory = frame.region(columnNumber);
+    validate(memory);
+    return new ColumnPlus(
+        column(frame, memory, columnType),
+        ColumnCapabilitiesImpl.createSimpleArrayColumnCapabilities(columnType),
+        frame.numRows()
+    );
+  }
+
+  abstract NumericArrayFrameColumn column(Frame frame, Memory memory, 
ColumnType columnType);
+
+  private void validate(final Memory region)
+  {
+    if (region.getCapacity() < NumericArrayFrameColumnWriter.DATA_OFFSET) {
+      throw DruidException.defensive("Column[%s] is not big enough for a 
header", columnNumber);
+    }
+    final byte typeCode = region.getByte(0);
+    if (typeCode != this.typeCode) {
+      throw DruidException.defensive(
+          "Column[%s] does not have the correct type code; expected[%s], 
got[%s]",
+          columnNumber,
+          this.typeCode,
+          typeCode
+      );
+    }
+  }
+
+  private static long getStartOfCumulativeLengthSection()
+  {
+    return NumericArrayFrameColumnWriter.DATA_OFFSET;
+  }
+
+  private static long getStartOfRowNullityData(final int numRows)
+  {
+    return getStartOfCumulativeLengthSection() + ((long) numRows * 
Integer.BYTES);
+  }
+
+  private static long getStartOfRowData(final Memory memory, final int numRows)
+  {
+    return getStartOfRowNullityData(numRows)
+           + (Byte.BYTES
+              * FrameColumnReaderUtils
+                  .getAdjustedCumulativeRowLength(memory, 
getStartOfCumulativeLengthSection(), numRows - 1));

Review Comment:
   ## Result of multiplication cast to wider type
   
   Potential overflow in [int multiplication](1) before it is converted to long 
by use in a numeric context.
   
   [Show more 
details](https://github.com/apache/druid/security/code-scanning/6576)



##########
processing/src/main/java/org/apache/druid/frame/write/columnar/NumericArrayFrameColumnWriter.java:
##########
@@ -0,0 +1,193 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.druid.frame.write.columnar;
+
+import org.apache.datasketches.memory.WritableMemory;
+import org.apache.druid.error.DruidException;
+import org.apache.druid.frame.allocation.AppendableMemory;
+import org.apache.druid.frame.allocation.MemoryAllocator;
+import org.apache.druid.frame.allocation.MemoryRange;
+import org.apache.druid.frame.write.FrameWriterUtils;
+import org.apache.druid.segment.ColumnValueSelector;
+
+import java.util.List;
+
+public abstract class NumericArrayFrameColumnWriter implements 
FrameColumnWriter
+{
+  /**
+   * Equivalent to {@link AppendableMemory#DEFAULT_INITIAL_ALLOCATION_SIZE} / 
3, since the memory would be further split
+   * up into three regions
+   */
+  private static final int INITIAL_ALLOCATION_SIZE = 120;
+
+  public static final byte NULL_ELEMENT_MARKER = 0x00;
+  public static final byte NON_NULL_ELEMENT_MARKER = 0x01;
+
+  /**
+   * A byte required at the beginning for type code
+   */
+  public static final long DATA_OFFSET = 1;
+
+  final ColumnValueSelector selector;
+  final MemoryAllocator allocator;
+  final byte typeCode;
+
+  /**
+   * Row lengths: one int per row with the number of values contained by that 
row and all previous rows.
+   * Only written for multi-value and array columns. When the corresponding 
row is null itself, the length is
+   * written as -(actual length) - 1. (Guaranteed to be a negative number even 
if "actual length" is zero.)
+   */
+  private final AppendableMemory cumulativeRowLengths;
+
+  /**
+   * Denotes if the element of the row is null or not
+   */
+  private final AppendableMemory rowNullityData;
+
+  /**
+   * Row data.
+   */
+  private final AppendableMemory rowData;
+
+  private int lastCumulativeRowLength = 0;
+  private int lastRowLength = -1;
+
+
+  public NumericArrayFrameColumnWriter(
+      final ColumnValueSelector selector,
+      final MemoryAllocator allocator,
+      final byte typeCode
+  )
+  {
+    this.selector = selector;
+    this.allocator = allocator;
+    this.typeCode = typeCode;
+    this.cumulativeRowLengths = AppendableMemory.create(allocator, 
INITIAL_ALLOCATION_SIZE);
+    this.rowNullityData = AppendableMemory.create(allocator, 
INITIAL_ALLOCATION_SIZE);
+    this.rowData = AppendableMemory.create(allocator, INITIAL_ALLOCATION_SIZE);
+  }
+
+  abstract int elementSizeBytes();
+
+  abstract void putNull(WritableMemory memory, long offset);
+
+  abstract void putArrayElement(WritableMemory memory, long offset, Number 
element);
+
+  @Override
+  public boolean addSelection()
+  {
+    List<? extends Number> numericArray = 
FrameWriterUtils.getNumericArrayFromObject(selector.getObject());
+    int rowLength = numericArray == null ? 0 : numericArray.size();
+
+    if ((long) lastCumulativeRowLength + rowLength > Integer.MAX_VALUE) {
+      return false;
+    }
+
+    if (!cumulativeRowLengths.reserveAdditional(Integer.BYTES)) {
+      return false;
+    }
+
+    if (!rowNullityData.reserveAdditional(rowLength * Byte.BYTES)) {
+      return false;
+    }
+
+    if (!rowData.reserveAdditional(rowLength * elementSizeBytes())) {
+      return false;
+    }
+
+    final MemoryRange<WritableMemory> rowLengthsCursor = 
cumulativeRowLengths.cursor();
+
+    if (numericArray == null) {
+      rowLengthsCursor.memory().putInt(rowLengthsCursor.start(), 
-(lastCumulativeRowLength + rowLength) - 1);
+    } else {
+      rowLengthsCursor.memory().putInt(rowLengthsCursor.start(), 
lastCumulativeRowLength + rowLength);
+    }
+    cumulativeRowLengths.advanceCursor(Integer.BYTES);
+    lastRowLength = rowLength;
+    lastCumulativeRowLength += rowLength;
+
+    final MemoryRange<WritableMemory> rowNullityDataCursor = rowLength > 0 ? 
rowNullityData.cursor() : null;
+    final MemoryRange<WritableMemory> rowDataCursor = rowLength > 0 ? 
rowData.cursor() : null;
+
+    for (int i = 0; i < rowLength; ++i) {
+      final Number element = numericArray.get(i);
+      final long memoryOffset = rowDataCursor.start() + ((long) 
elementSizeBytes() * i);
+      if (element == null) {
+        rowNullityDataCursor.memory().putByte(rowNullityDataCursor.start() + 
Byte.BYTES * i, NULL_ELEMENT_MARKER);
+        putNull(rowDataCursor.memory(), memoryOffset);
+      } else {
+        rowNullityDataCursor.memory().putByte(rowNullityDataCursor.start() + 
Byte.BYTES * i, NON_NULL_ELEMENT_MARKER);

Review Comment:
   ## Result of multiplication cast to wider type
   
   Potential overflow in [int multiplication](1) before it is converted to long 
by use in a numeric context.
   
   [Show more 
details](https://github.com/apache/druid/security/code-scanning/6579)



##########
processing/src/main/java/org/apache/druid/frame/read/columnar/NumericArrayFrameColumnReader.java:
##########
@@ -0,0 +1,313 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.druid.frame.read.columnar;
+
+import it.unimi.dsi.fastutil.objects.ObjectArrays;
+import org.apache.datasketches.memory.Memory;
+import org.apache.druid.error.DruidException;
+import org.apache.druid.frame.Frame;
+import org.apache.druid.frame.write.columnar.NumericArrayFrameColumnWriter;
+import org.apache.druid.query.monomorphicprocessing.RuntimeShapeInspector;
+import org.apache.druid.query.rowsandcols.column.Column;
+import org.apache.druid.query.rowsandcols.column.ColumnAccessorBasedColumn;
+import 
org.apache.druid.query.rowsandcols.column.accessor.ObjectColumnAccessorBase;
+import org.apache.druid.segment.ColumnValueSelector;
+import org.apache.druid.segment.ObjectColumnSelector;
+import org.apache.druid.segment.column.BaseColumn;
+import org.apache.druid.segment.column.ColumnCapabilitiesImpl;
+import org.apache.druid.segment.column.ColumnType;
+import org.apache.druid.segment.data.ReadableOffset;
+import org.apache.druid.segment.vector.ReadableVectorInspector;
+import org.apache.druid.segment.vector.ReadableVectorOffset;
+import org.apache.druid.segment.vector.VectorObjectSelector;
+
+import javax.annotation.Nullable;
+import java.io.IOException;
+import java.util.Comparator;
+
+public abstract class NumericArrayFrameColumnReader implements 
FrameColumnReader
+{
+  private final byte typeCode;
+  private final ColumnType columnType;
+  private final int columnNumber;
+
+  public NumericArrayFrameColumnReader(byte typeCode, ColumnType columnType, 
int columnNumber)
+  {
+    this.typeCode = typeCode;
+    this.columnType = columnType;
+    this.columnNumber = columnNumber;
+  }
+
+  @Override
+  public Column readRACColumn(Frame frame)
+  {
+    final Memory memory = frame.region(columnNumber);
+    validate(memory);
+    return new ColumnAccessorBasedColumn(column(frame, memory, columnType));
+  }
+
+  @Override
+  public ColumnPlus readColumn(Frame frame)
+  {
+    final Memory memory = frame.region(columnNumber);
+    validate(memory);
+    return new ColumnPlus(
+        column(frame, memory, columnType),
+        ColumnCapabilitiesImpl.createSimpleArrayColumnCapabilities(columnType),
+        frame.numRows()
+    );
+  }
+
+  abstract NumericArrayFrameColumn column(Frame frame, Memory memory, 
ColumnType columnType);
+
+  private void validate(final Memory region)
+  {
+    if (region.getCapacity() < NumericArrayFrameColumnWriter.DATA_OFFSET) {
+      throw DruidException.defensive("Column[%s] is not big enough for a 
header", columnNumber);
+    }
+    final byte typeCode = region.getByte(0);
+    if (typeCode != this.typeCode) {
+      throw DruidException.defensive(
+          "Column[%s] does not have the correct type code; expected[%s], 
got[%s]",
+          columnNumber,
+          this.typeCode,
+          typeCode
+      );
+    }
+  }
+
+  private static long getStartOfCumulativeLengthSection()
+  {
+    return NumericArrayFrameColumnWriter.DATA_OFFSET;
+  }
+
+  private static long getStartOfRowNullityData(final int numRows)
+  {
+    return getStartOfCumulativeLengthSection() + ((long) numRows * 
Integer.BYTES);
+  }
+
+  private static long getStartOfRowData(final Memory memory, final int numRows)
+  {
+    return getStartOfRowNullityData(numRows)
+           + (Byte.BYTES
+              * FrameColumnReaderUtils
+                  .getAdjustedCumulativeRowLength(memory, 
getStartOfCumulativeLengthSection(), numRows - 1));
+  }
+
+  public abstract static class NumericArrayFrameColumn extends 
ObjectColumnAccessorBase implements BaseColumn
+  {
+
+    private final Frame frame;
+    private final Memory memory;
+    private final ColumnType columnType;
+
+    private final long rowNullityDataOffset;
+    private final long rowDataOffset;
+
+
+    public NumericArrayFrameColumn(Frame frame, Memory memory, ColumnType 
columnType)
+    {
+      this.frame = frame;
+      this.memory = memory;
+      this.columnType = columnType;
+
+      this.rowNullityDataOffset = getStartOfRowNullityData(frame.numRows());
+      this.rowDataOffset = getStartOfRowData(memory, frame.numRows());
+    }
+
+    @Override
+    public ColumnType getType()
+    {
+      return columnType;
+    }
+
+    @Override
+    public int numRows()
+    {
+      return frame.numRows();
+    }
+
+    @Override
+    protected Object getVal(int rowNum)
+    {
+      return getNumericArray(physicalRow(rowNum));
+    }
+
+    @Override
+    protected Comparator<Object> getComparator()
+    {
+      return columnType.getNullableStrategy();
+    }
+
+    @Override
+    public ColumnValueSelector<?> makeColumnValueSelector(ReadableOffset 
offset)
+    {
+      return new ObjectColumnSelector<Object>()
+      {
+        private int cachedLogicalRow = -1;
+        @Nullable
+        private Object[] cachedValue = null;
+
+        @Override
+        public void inspectRuntimeShape(RuntimeShapeInspector inspector)
+        {
+        }
+
+        @Nullable
+        @Override
+        public Object getObject()
+        {
+          compute();
+          return cachedValue;
+        }
+
+        @Override
+        public Class<?> classOfObject()
+        {
+          return Object[].class;
+        }
+
+        private void compute()
+        {
+          int currentLogicalRow = offset.getOffset();
+          if (cachedLogicalRow == currentLogicalRow) {
+            return;
+          }
+          cachedValue = getNumericArray(physicalRow(currentLogicalRow));
+          cachedLogicalRow = currentLogicalRow;
+        }
+      };
+    }
+
+    @Override
+    public VectorObjectSelector makeVectorObjectSelector(ReadableVectorOffset 
offset)
+    {
+      return new VectorObjectSelector()
+      {
+        private final Object[] vector = new Object[offset.getMaxVectorSize()];
+        private int id = ReadableVectorInspector.NULL_ID;
+
+        @Override
+        public Object[] getObjectVector()
+        {
+          computeVector();
+          return vector;
+        }
+
+        @Override
+        public int getMaxVectorSize()
+        {
+          return offset.getMaxVectorSize();
+        }
+
+        @Override
+        public int getCurrentVectorSize()
+        {
+          return offset.getCurrentVectorSize();
+        }
+
+        private void computeVector()
+        {
+          if (id == offset.getId()) {
+            return;
+          }
+
+          if (offset.isContiguous()) {
+            // Contiguous offsets can have a cache optimized implementation if 
'frame.isPermuted() == false',
+            // i.e. logicalRow == physicalRow. The implementation can 
separately fetch out the nullity data, and the
+            // element data continguously.
+            final int start = offset.getStartOffset();
+            for (int i = 0; i < offset.getCurrentVectorSize(); ++i) {
+              vector[i] = getNumericArray(physicalRow(start + i));
+            }
+          } else {
+            final int[] offsets = offset.getOffsets();
+            for (int i = 0; i < offset.getCurrentVectorSize(); ++i) {
+              vector[i] = getNumericArray(physicalRow(offsets[i]));
+            }
+
+            id = offset.getId();
+          }
+        }
+      };
+    }
+
+    @Override
+    public void close() throws IOException
+    {
+
+    }
+
+    private int physicalRow(int logicalRow)
+    {
+      return frame.physicalRow(logicalRow);
+    }
+
+    @Nullable
+    private Object[] getNumericArray(final int physicalRow)
+    {
+      final int cumulativeLength = 
FrameColumnReaderUtils.getCumulativeRowLength(
+          memory,
+          getStartOfCumulativeLengthSection(),
+          physicalRow
+      );
+
+      final int rowLength;
+      if (FrameColumnReaderUtils.isNullRow(cumulativeLength)) {
+        return null;
+      } else if (physicalRow == 0) {
+        rowLength = cumulativeLength;
+      } else {
+        final int previousCumulativeLength = 
FrameColumnReaderUtils.adjustCumulativeRowLength(
+            FrameColumnReaderUtils.getCumulativeRowLength(
+                memory,
+                getStartOfCumulativeLengthSection(),
+                physicalRow - 1
+            )
+        );
+        rowLength = cumulativeLength - previousCumulativeLength;
+      }
+
+      if (rowLength == 0) {
+        return ObjectArrays.EMPTY_ARRAY;
+      }
+
+      final Object[] row = new Object[rowLength];
+      for (int i = 0; i < rowLength; ++i) {
+        final int cumulativeIndex = cumulativeLength - rowLength + i;
+        row[i] = getElementNullity(cumulativeIndex) ? null : 
getElement(memory, rowDataOffset, cumulativeIndex);
+      }
+
+      return row;
+    }
+
+    private boolean getElementNullity(final int cumulativeIndex)
+    {
+      byte b = memory.getByte(rowNullityDataOffset + cumulativeIndex * 
Byte.BYTES);

Review Comment:
   ## Result of multiplication cast to wider type
   
   Potential overflow in [int multiplication](1) before it is converted to long 
by use in a numeric context.
   
   [Show more 
details](https://github.com/apache/druid/security/code-scanning/6577)



##########
processing/src/main/java/org/apache/druid/frame/read/columnar/FloatArrayFrameColumnReader.java:
##########
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.druid.frame.read.columnar;
+
+import org.apache.datasketches.memory.Memory;
+import org.apache.druid.frame.Frame;
+import org.apache.druid.frame.write.columnar.FrameColumnWriters;
+import org.apache.druid.segment.column.ColumnType;
+
+public class FloatArrayFrameColumnReader extends NumericArrayFrameColumnReader
+{
+  public FloatArrayFrameColumnReader(int columnNumber)
+  {
+    super(FrameColumnWriters.TYPE_FLOAT_ARRAY, ColumnType.FLOAT_ARRAY, 
columnNumber);
+  }
+
+  @Override
+  NumericArrayFrameColumn column(Frame frame, Memory memory, ColumnType 
columnType)
+  {
+    return new FloatArrayFrameColumn(frame, memory, columnType);
+  }
+
+  private static class FloatArrayFrameColumn extends NumericArrayFrameColumn
+  {
+    public FloatArrayFrameColumn(
+        Frame frame,
+        Memory memory,
+        ColumnType columnType
+    )
+    {
+      super(frame, memory, columnType);
+    }
+
+    @Override
+    Number getElement(Memory memory, long rowDataOffset, int cumulativeIndex)
+    {
+      return memory.getFloat(rowDataOffset + (long) cumulativeIndex * 
Float.BYTES);

Review Comment:
   ## User-controlled data in arithmetic expression
   
   This arithmetic expression depends on a [user-provided value](1), 
potentially causing an overflow.
   This arithmetic expression depends on a [user-provided value](2), 
potentially causing an overflow.
   
   [Show more 
details](https://github.com/apache/druid/security/code-scanning/6585)



##########
processing/src/main/java/org/apache/druid/frame/read/columnar/NumericArrayFrameColumnReader.java:
##########
@@ -0,0 +1,313 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.druid.frame.read.columnar;
+
+import it.unimi.dsi.fastutil.objects.ObjectArrays;
+import org.apache.datasketches.memory.Memory;
+import org.apache.druid.error.DruidException;
+import org.apache.druid.frame.Frame;
+import org.apache.druid.frame.write.columnar.NumericArrayFrameColumnWriter;
+import org.apache.druid.query.monomorphicprocessing.RuntimeShapeInspector;
+import org.apache.druid.query.rowsandcols.column.Column;
+import org.apache.druid.query.rowsandcols.column.ColumnAccessorBasedColumn;
+import 
org.apache.druid.query.rowsandcols.column.accessor.ObjectColumnAccessorBase;
+import org.apache.druid.segment.ColumnValueSelector;
+import org.apache.druid.segment.ObjectColumnSelector;
+import org.apache.druid.segment.column.BaseColumn;
+import org.apache.druid.segment.column.ColumnCapabilitiesImpl;
+import org.apache.druid.segment.column.ColumnType;
+import org.apache.druid.segment.data.ReadableOffset;
+import org.apache.druid.segment.vector.ReadableVectorInspector;
+import org.apache.druid.segment.vector.ReadableVectorOffset;
+import org.apache.druid.segment.vector.VectorObjectSelector;
+
+import javax.annotation.Nullable;
+import java.io.IOException;
+import java.util.Comparator;
+
+public abstract class NumericArrayFrameColumnReader implements 
FrameColumnReader
+{
+  private final byte typeCode;
+  private final ColumnType columnType;
+  private final int columnNumber;
+
+  public NumericArrayFrameColumnReader(byte typeCode, ColumnType columnType, 
int columnNumber)
+  {
+    this.typeCode = typeCode;
+    this.columnType = columnType;
+    this.columnNumber = columnNumber;
+  }
+
+  @Override
+  public Column readRACColumn(Frame frame)
+  {
+    final Memory memory = frame.region(columnNumber);
+    validate(memory);
+    return new ColumnAccessorBasedColumn(column(frame, memory, columnType));
+  }
+
+  @Override
+  public ColumnPlus readColumn(Frame frame)
+  {
+    final Memory memory = frame.region(columnNumber);
+    validate(memory);
+    return new ColumnPlus(
+        column(frame, memory, columnType),
+        ColumnCapabilitiesImpl.createSimpleArrayColumnCapabilities(columnType),
+        frame.numRows()
+    );
+  }
+
+  abstract NumericArrayFrameColumn column(Frame frame, Memory memory, 
ColumnType columnType);
+
+  private void validate(final Memory region)
+  {
+    if (region.getCapacity() < NumericArrayFrameColumnWriter.DATA_OFFSET) {
+      throw DruidException.defensive("Column[%s] is not big enough for a 
header", columnNumber);
+    }
+    final byte typeCode = region.getByte(0);
+    if (typeCode != this.typeCode) {
+      throw DruidException.defensive(
+          "Column[%s] does not have the correct type code; expected[%s], 
got[%s]",
+          columnNumber,
+          this.typeCode,
+          typeCode
+      );
+    }
+  }
+
+  private static long getStartOfCumulativeLengthSection()
+  {
+    return NumericArrayFrameColumnWriter.DATA_OFFSET;
+  }
+
+  private static long getStartOfRowNullityData(final int numRows)
+  {
+    return getStartOfCumulativeLengthSection() + ((long) numRows * 
Integer.BYTES);
+  }
+
+  private static long getStartOfRowData(final Memory memory, final int numRows)
+  {
+    return getStartOfRowNullityData(numRows)
+           + (Byte.BYTES
+              * FrameColumnReaderUtils
+                  .getAdjustedCumulativeRowLength(memory, 
getStartOfCumulativeLengthSection(), numRows - 1));

Review Comment:
   ## User-controlled data in arithmetic expression
   
   This arithmetic expression depends on a [user-provided value](1), 
potentially causing an underflow.
   This arithmetic expression depends on a [user-provided value](2), 
potentially causing an underflow.
   
   [Show more 
details](https://github.com/apache/druid/security/code-scanning/6587)



##########
processing/src/main/java/org/apache/druid/frame/read/columnar/NumericArrayFrameColumnReader.java:
##########
@@ -0,0 +1,313 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.druid.frame.read.columnar;
+
+import it.unimi.dsi.fastutil.objects.ObjectArrays;
+import org.apache.datasketches.memory.Memory;
+import org.apache.druid.error.DruidException;
+import org.apache.druid.frame.Frame;
+import org.apache.druid.frame.write.columnar.NumericArrayFrameColumnWriter;
+import org.apache.druid.query.monomorphicprocessing.RuntimeShapeInspector;
+import org.apache.druid.query.rowsandcols.column.Column;
+import org.apache.druid.query.rowsandcols.column.ColumnAccessorBasedColumn;
+import 
org.apache.druid.query.rowsandcols.column.accessor.ObjectColumnAccessorBase;
+import org.apache.druid.segment.ColumnValueSelector;
+import org.apache.druid.segment.ObjectColumnSelector;
+import org.apache.druid.segment.column.BaseColumn;
+import org.apache.druid.segment.column.ColumnCapabilitiesImpl;
+import org.apache.druid.segment.column.ColumnType;
+import org.apache.druid.segment.data.ReadableOffset;
+import org.apache.druid.segment.vector.ReadableVectorInspector;
+import org.apache.druid.segment.vector.ReadableVectorOffset;
+import org.apache.druid.segment.vector.VectorObjectSelector;
+
+import javax.annotation.Nullable;
+import java.io.IOException;
+import java.util.Comparator;
+
+public abstract class NumericArrayFrameColumnReader implements 
FrameColumnReader
+{
+  private final byte typeCode;
+  private final ColumnType columnType;
+  private final int columnNumber;
+
+  public NumericArrayFrameColumnReader(byte typeCode, ColumnType columnType, 
int columnNumber)
+  {
+    this.typeCode = typeCode;
+    this.columnType = columnType;
+    this.columnNumber = columnNumber;
+  }
+
+  @Override
+  public Column readRACColumn(Frame frame)
+  {
+    final Memory memory = frame.region(columnNumber);
+    validate(memory);
+    return new ColumnAccessorBasedColumn(column(frame, memory, columnType));
+  }
+
+  @Override
+  public ColumnPlus readColumn(Frame frame)
+  {
+    final Memory memory = frame.region(columnNumber);
+    validate(memory);
+    return new ColumnPlus(
+        column(frame, memory, columnType),
+        ColumnCapabilitiesImpl.createSimpleArrayColumnCapabilities(columnType),
+        frame.numRows()
+    );
+  }
+
+  abstract NumericArrayFrameColumn column(Frame frame, Memory memory, 
ColumnType columnType);
+
+  private void validate(final Memory region)
+  {
+    if (region.getCapacity() < NumericArrayFrameColumnWriter.DATA_OFFSET) {
+      throw DruidException.defensive("Column[%s] is not big enough for a 
header", columnNumber);
+    }
+    final byte typeCode = region.getByte(0);
+    if (typeCode != this.typeCode) {
+      throw DruidException.defensive(
+          "Column[%s] does not have the correct type code; expected[%s], 
got[%s]",
+          columnNumber,
+          this.typeCode,
+          typeCode
+      );
+    }
+  }
+
+  private static long getStartOfCumulativeLengthSection()
+  {
+    return NumericArrayFrameColumnWriter.DATA_OFFSET;
+  }
+
+  private static long getStartOfRowNullityData(final int numRows)
+  {
+    return getStartOfCumulativeLengthSection() + ((long) numRows * 
Integer.BYTES);
+  }
+
+  private static long getStartOfRowData(final Memory memory, final int numRows)
+  {
+    return getStartOfRowNullityData(numRows)
+           + (Byte.BYTES
+              * FrameColumnReaderUtils
+                  .getAdjustedCumulativeRowLength(memory, 
getStartOfCumulativeLengthSection(), numRows - 1));
+  }
+
+  public abstract static class NumericArrayFrameColumn extends 
ObjectColumnAccessorBase implements BaseColumn
+  {
+
+    private final Frame frame;
+    private final Memory memory;
+    private final ColumnType columnType;
+
+    private final long rowNullityDataOffset;
+    private final long rowDataOffset;
+
+
+    public NumericArrayFrameColumn(Frame frame, Memory memory, ColumnType 
columnType)
+    {
+      this.frame = frame;
+      this.memory = memory;
+      this.columnType = columnType;
+
+      this.rowNullityDataOffset = getStartOfRowNullityData(frame.numRows());
+      this.rowDataOffset = getStartOfRowData(memory, frame.numRows());
+    }
+
+    @Override
+    public ColumnType getType()
+    {
+      return columnType;
+    }
+
+    @Override
+    public int numRows()
+    {
+      return frame.numRows();
+    }
+
+    @Override
+    protected Object getVal(int rowNum)
+    {
+      return getNumericArray(physicalRow(rowNum));
+    }
+
+    @Override
+    protected Comparator<Object> getComparator()
+    {
+      return columnType.getNullableStrategy();
+    }
+
+    @Override
+    public ColumnValueSelector<?> makeColumnValueSelector(ReadableOffset 
offset)
+    {
+      return new ObjectColumnSelector<Object>()
+      {
+        private int cachedLogicalRow = -1;
+        @Nullable
+        private Object[] cachedValue = null;
+
+        @Override
+        public void inspectRuntimeShape(RuntimeShapeInspector inspector)
+        {
+        }
+
+        @Nullable
+        @Override
+        public Object getObject()
+        {
+          compute();
+          return cachedValue;
+        }
+
+        @Override
+        public Class<?> classOfObject()
+        {
+          return Object[].class;
+        }
+
+        private void compute()
+        {
+          int currentLogicalRow = offset.getOffset();
+          if (cachedLogicalRow == currentLogicalRow) {
+            return;
+          }
+          cachedValue = getNumericArray(physicalRow(currentLogicalRow));
+          cachedLogicalRow = currentLogicalRow;
+        }
+      };
+    }
+
+    @Override
+    public VectorObjectSelector makeVectorObjectSelector(ReadableVectorOffset 
offset)
+    {
+      return new VectorObjectSelector()
+      {
+        private final Object[] vector = new Object[offset.getMaxVectorSize()];
+        private int id = ReadableVectorInspector.NULL_ID;
+
+        @Override
+        public Object[] getObjectVector()
+        {
+          computeVector();
+          return vector;
+        }
+
+        @Override
+        public int getMaxVectorSize()
+        {
+          return offset.getMaxVectorSize();
+        }
+
+        @Override
+        public int getCurrentVectorSize()
+        {
+          return offset.getCurrentVectorSize();
+        }
+
+        private void computeVector()
+        {
+          if (id == offset.getId()) {
+            return;
+          }
+
+          if (offset.isContiguous()) {
+            // Contiguous offsets can have a cache optimized implementation if 
'frame.isPermuted() == false',
+            // i.e. logicalRow == physicalRow. The implementation can 
separately fetch out the nullity data, and the
+            // element data continguously.
+            final int start = offset.getStartOffset();
+            for (int i = 0; i < offset.getCurrentVectorSize(); ++i) {
+              vector[i] = getNumericArray(physicalRow(start + i));
+            }
+          } else {
+            final int[] offsets = offset.getOffsets();
+            for (int i = 0; i < offset.getCurrentVectorSize(); ++i) {
+              vector[i] = getNumericArray(physicalRow(offsets[i]));
+            }
+
+            id = offset.getId();
+          }
+        }
+      };
+    }
+
+    @Override
+    public void close() throws IOException
+    {
+
+    }
+
+    private int physicalRow(int logicalRow)
+    {
+      return frame.physicalRow(logicalRow);
+    }
+
+    @Nullable
+    private Object[] getNumericArray(final int physicalRow)
+    {
+      final int cumulativeLength = 
FrameColumnReaderUtils.getCumulativeRowLength(
+          memory,
+          getStartOfCumulativeLengthSection(),
+          physicalRow
+      );
+
+      final int rowLength;
+      if (FrameColumnReaderUtils.isNullRow(cumulativeLength)) {
+        return null;
+      } else if (physicalRow == 0) {
+        rowLength = cumulativeLength;
+      } else {
+        final int previousCumulativeLength = 
FrameColumnReaderUtils.adjustCumulativeRowLength(
+            FrameColumnReaderUtils.getCumulativeRowLength(
+                memory,
+                getStartOfCumulativeLengthSection(),
+                physicalRow - 1
+            )
+        );
+        rowLength = cumulativeLength - previousCumulativeLength;
+      }
+
+      if (rowLength == 0) {
+        return ObjectArrays.EMPTY_ARRAY;
+      }
+
+      final Object[] row = new Object[rowLength];
+      for (int i = 0; i < rowLength; ++i) {
+        final int cumulativeIndex = cumulativeLength - rowLength + i;
+        row[i] = getElementNullity(cumulativeIndex) ? null : 
getElement(memory, rowDataOffset, cumulativeIndex);
+      }
+
+      return row;
+    }
+
+    private boolean getElementNullity(final int cumulativeIndex)
+    {
+      byte b = memory.getByte(rowNullityDataOffset + cumulativeIndex * 
Byte.BYTES);

Review Comment:
   ## User-controlled data in arithmetic expression
   
   This arithmetic expression depends on a [user-provided value](1), 
potentially causing an overflow.
   This arithmetic expression depends on a [user-provided value](2), 
potentially causing an overflow.
   
   [Show more 
details](https://github.com/apache/druid/security/code-scanning/6588)



##########
processing/src/main/java/org/apache/druid/frame/write/columnar/NumericArrayFrameColumnWriter.java:
##########
@@ -0,0 +1,193 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.druid.frame.write.columnar;
+
+import org.apache.datasketches.memory.WritableMemory;
+import org.apache.druid.error.DruidException;
+import org.apache.druid.frame.allocation.AppendableMemory;
+import org.apache.druid.frame.allocation.MemoryAllocator;
+import org.apache.druid.frame.allocation.MemoryRange;
+import org.apache.druid.frame.write.FrameWriterUtils;
+import org.apache.druid.segment.ColumnValueSelector;
+
+import java.util.List;
+
+public abstract class NumericArrayFrameColumnWriter implements 
FrameColumnWriter
+{
+  /**
+   * Equivalent to {@link AppendableMemory#DEFAULT_INITIAL_ALLOCATION_SIZE} / 
3, since the memory would be further split
+   * up into three regions
+   */
+  private static final int INITIAL_ALLOCATION_SIZE = 120;
+
+  public static final byte NULL_ELEMENT_MARKER = 0x00;
+  public static final byte NON_NULL_ELEMENT_MARKER = 0x01;
+
+  /**
+   * A byte required at the beginning for type code
+   */
+  public static final long DATA_OFFSET = 1;
+
+  final ColumnValueSelector selector;
+  final MemoryAllocator allocator;
+  final byte typeCode;
+
+  /**
+   * Row lengths: one int per row with the number of values contained by that 
row and all previous rows.
+   * Only written for multi-value and array columns. When the corresponding 
row is null itself, the length is
+   * written as -(actual length) - 1. (Guaranteed to be a negative number even 
if "actual length" is zero.)
+   */
+  private final AppendableMemory cumulativeRowLengths;
+
+  /**
+   * Denotes if the element of the row is null or not
+   */
+  private final AppendableMemory rowNullityData;
+
+  /**
+   * Row data.
+   */
+  private final AppendableMemory rowData;
+
+  private int lastCumulativeRowLength = 0;
+  private int lastRowLength = -1;
+
+
+  public NumericArrayFrameColumnWriter(
+      final ColumnValueSelector selector,
+      final MemoryAllocator allocator,
+      final byte typeCode
+  )
+  {
+    this.selector = selector;
+    this.allocator = allocator;
+    this.typeCode = typeCode;
+    this.cumulativeRowLengths = AppendableMemory.create(allocator, 
INITIAL_ALLOCATION_SIZE);
+    this.rowNullityData = AppendableMemory.create(allocator, 
INITIAL_ALLOCATION_SIZE);
+    this.rowData = AppendableMemory.create(allocator, INITIAL_ALLOCATION_SIZE);
+  }
+
+  abstract int elementSizeBytes();
+
+  abstract void putNull(WritableMemory memory, long offset);
+
+  abstract void putArrayElement(WritableMemory memory, long offset, Number 
element);
+
+  @Override
+  public boolean addSelection()
+  {
+    List<? extends Number> numericArray = 
FrameWriterUtils.getNumericArrayFromObject(selector.getObject());
+    int rowLength = numericArray == null ? 0 : numericArray.size();
+
+    if ((long) lastCumulativeRowLength + rowLength > Integer.MAX_VALUE) {
+      return false;
+    }
+
+    if (!cumulativeRowLengths.reserveAdditional(Integer.BYTES)) {
+      return false;
+    }
+
+    if (!rowNullityData.reserveAdditional(rowLength * Byte.BYTES)) {
+      return false;
+    }
+
+    if (!rowData.reserveAdditional(rowLength * elementSizeBytes())) {
+      return false;
+    }
+
+    final MemoryRange<WritableMemory> rowLengthsCursor = 
cumulativeRowLengths.cursor();
+
+    if (numericArray == null) {
+      rowLengthsCursor.memory().putInt(rowLengthsCursor.start(), 
-(lastCumulativeRowLength + rowLength) - 1);
+    } else {
+      rowLengthsCursor.memory().putInt(rowLengthsCursor.start(), 
lastCumulativeRowLength + rowLength);
+    }
+    cumulativeRowLengths.advanceCursor(Integer.BYTES);
+    lastRowLength = rowLength;
+    lastCumulativeRowLength += rowLength;
+
+    final MemoryRange<WritableMemory> rowNullityDataCursor = rowLength > 0 ? 
rowNullityData.cursor() : null;
+    final MemoryRange<WritableMemory> rowDataCursor = rowLength > 0 ? 
rowData.cursor() : null;
+
+    for (int i = 0; i < rowLength; ++i) {
+      final Number element = numericArray.get(i);
+      final long memoryOffset = rowDataCursor.start() + ((long) 
elementSizeBytes() * i);
+      if (element == null) {
+        rowNullityDataCursor.memory().putByte(rowNullityDataCursor.start() + 
Byte.BYTES * i, NULL_ELEMENT_MARKER);
+        putNull(rowDataCursor.memory(), memoryOffset);
+      } else {
+        rowNullityDataCursor.memory().putByte(rowNullityDataCursor.start() + 
Byte.BYTES * i, NON_NULL_ELEMENT_MARKER);

Review Comment:
   ## Dereferenced variable may be null
   
   Variable [rowNullityDataCursor](1) may be null at this access because of 
[this](2) assignment.
   
   [Show more 
details](https://github.com/apache/druid/security/code-scanning/6582)



##########
processing/src/main/java/org/apache/druid/frame/read/columnar/StringFrameColumnReader.java:
##########
@@ -231,7 +201,9 @@
     final int totalNumValues;
 
     if (multiValue) {
-      totalNumValues = 
adjustCumulativeRowLength(getCumulativeRowLength(memory, numRows - 1));
+      totalNumValues = FrameColumnReaderUtils.adjustCumulativeRowLength(
+          FrameColumnReaderUtils.getCumulativeRowLength(memory, 
getStartOfCumulativeLengthSection(), numRows - 1)

Review Comment:
   ## User-controlled data in arithmetic expression
   
   This arithmetic expression depends on a [user-provided value](1), 
potentially causing an underflow.
   This arithmetic expression depends on a [user-provided value](2), 
potentially causing an underflow.
   
   [Show more 
details](https://github.com/apache/druid/security/code-scanning/6589)



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to