Skip to content

Commit 8ddce0a

Browse files
committed
check bounds in getChildAt(i) to avoid NPEs
1 parent f1dead0 commit 8ddce0a

File tree

5 files changed

+53
-37
lines changed

5 files changed

+53
-37
lines changed

js/src/predicate.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ export class Col<T= any> extends Value<T> {
6161
}
6262
if (this.colidx < 0) { throw new Error(`Failed to bind Col "${this.name}"`); }
6363
}
64-
this.vector = batch.getChildAt(this.colidx);
64+
this.vector = batch.getChildAt(this.colidx)!;
6565
return this.vector.get.bind(this.vector);
6666
}
6767

js/src/recordbatch.ts

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
// specific language governing permissions and limitations
1616
// under the License.
1717

18-
import { Schema, Struct } from './type';
18+
import { Schema, Struct, DataType } from './type';
1919
import { flatbuffers } from 'flatbuffers';
2020
import { View, Vector, StructVector } from './vector';
2121
import { Data, NestedData } from './data';
@@ -40,34 +40,31 @@ export class RecordBatch extends StructVector {
4040
super(data, args[2]);
4141
this.schema = args[0];
4242
this.length = data.length;
43-
this.numCols = this.schema.fields.length;
4443
} else {
4544
const [schema, numRows, cols] = args;
46-
const columns: Vector<any>[] = new Array(cols.length);
47-
const columnsData: Data<any>[] = new Array(cols.length);
45+
const childData: Data<any>[] = new Array(cols.length);
4846
for (let index = -1, length = cols.length; ++index < length;) {
4947
const col: Data<any> | Vector = cols[index];
50-
if (col instanceof Vector) {
51-
columnsData[index] = (columns[index] = col as Vector).data;
52-
} else {
53-
columns[index] = Vector.create(columnsData[index] = col);
54-
}
48+
childData[index] = col instanceof Vector ? col.data : col;
5549
}
56-
super(new NestedData(new Struct(schema.fields), numRows, null, columnsData));
50+
super(new NestedData(new Struct(schema.fields), numRows, null, childData));
5751
this.schema = schema;
5852
this.length = numRows;
59-
this.numCols = schema.fields.length;
6053
}
54+
this.numCols = this.schema.fields.length;
6155
}
6256
public clone<R extends Struct>(data: Data<R>, view: View<R> = this.view.clone(data)): this {
6357
return new RecordBatch(this.schema, data as any, view) as any;
6458
}
59+
public getChildAt<R extends DataType = DataType>(index: number): Vector<R> | null {
60+
return index < 0 || index >= this.numCols ? null : super.getChildAt<R>(index);
61+
}
6562
public select(...columnNames: string[]) {
6663
const fields = this.schema.fields;
6764
const namesToKeep = columnNames.reduce((xs, x) => (xs[x] = true) && xs, Object.create(null));
6865
return new RecordBatch(
6966
this.schema.select(...columnNames), this.length,
70-
this.childData.filter((_, index) => namesToKeep[fields[index].name])
67+
this.childData.filter((_, i) => namesToKeep[fields[i].name])
7168
);
7269
}
7370
}

js/src/table.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,9 @@ export class Table implements DataFrame {
6565
static fromStruct(struct: StructVector) {
6666
const schema = new Schema(struct.type.children);
6767
const chunks = struct.view instanceof ChunkedView ?
68-
(struct.view.childVectors as StructVector[]) :
68+
(struct.view.chunkVectors as StructVector[]) :
6969
[struct];
70-
return new Table(chunks.map((chunk)=>new RecordBatch(schema, chunk.length, chunk.view.childData)));
70+
return new Table(chunks.map((chunk) => new RecordBatch(schema, chunk.length, chunk.view.childData)));
7171
}
7272

7373
public readonly schema: Schema;
@@ -102,7 +102,6 @@ export class Table implements DataFrame {
102102
this.schema = schema;
103103
this.batches = batches;
104104
this.batchesUnion = batches.reduce((union, batch) => union.concat(batch));
105-
// this.columns = schema.fields.map((_, i) => this.batchesUnion.getChildAt(i));
106105
this.length = this.batchesUnion.length;
107106
this.numCols = this.batchesUnion.numCols;
108107
}
@@ -113,8 +112,10 @@ export class Table implements DataFrame {
113112
return this.getColumnAt(this.getColumnIndex(name));
114113
}
115114
public getColumnAt(index: number) {
116-
return this._columns[index] || (
117-
this._columns[index] = this.batchesUnion.getChildAt(index));
115+
return index < 0 || index >= this.numCols
116+
? null
117+
: this._columns[index] || (
118+
this._columns[index] = this.batchesUnion.getChildAt(index)!);
118119
}
119120
public getColumnIndex(name: string) {
120121
return this.schema.fields.findIndex((f) => f.name === name);
@@ -271,8 +272,8 @@ export class CountByResult extends Table implements DataFrame {
271272
));
272273
}
273274
public toJSON(): Object {
274-
const values = this.getColumnAt(0);
275-
const counts = this.getColumnAt(1);
275+
const values = this.getColumnAt(0)!;
276+
const counts = this.getColumnAt(1)!;
276277
const result = {} as { [k: string]: number | null };
277278
for (let i = -1; ++i < this.length;) {
278279
result[values.get(i)] = counts.get(i);

js/src/vector.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ export class Vector<T extends DataType = any> implements VectorLike, View<T>, Vi
3535
public static create<T extends DataType>(data: Data<T>): Vector<T> {
3636
return createVector(data);
3737
}
38-
public static concat<T extends DataType>(...sources: Vector<T>[]): Vector<T> {
39-
return sources.length === 1 ? sources[0] : sources.reduce((a, b) => a.concat(b));
38+
public static concat<T extends DataType>(source?: Vector<T> | null, ...others: Vector<T>[]): Vector<T> {
39+
return others.reduce((a, b) => a ? a.concat(b) : b, source!);
4040
}
4141
public type: T;
4242
public length: number;

js/src/vector/nested.ts

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,15 @@ export abstract class NestedView<T extends NestedType> implements View<T> {
2424
public length: number;
2525
public numChildren: number;
2626
public childData: Data<any>[];
27-
protected _childColumns: Vector<any>[];
27+
protected _children: Vector<any>[];
2828
constructor(data: Data<T>, children?: Vector<any>[]) {
2929
this.length = data.length;
3030
this.childData = data.childData;
3131
this.numChildren = data.childData.length;
32-
this._childColumns = children || new Array(this.numChildren);
32+
this._children = children || new Array(this.numChildren);
3333
}
3434
public clone(data: Data<T>): this {
35-
return new (<any> this.constructor)(data, this._childColumns) as this;
35+
return new (<any> this.constructor)(data, this._children) as this;
3636
}
3737
public isValid(): boolean {
3838
return true;
@@ -52,9 +52,11 @@ export abstract class NestedView<T extends NestedType> implements View<T> {
5252
}
5353
protected abstract getNested(self: NestedView<T>, index: number): T['TValue'];
5454
protected abstract setNested(self: NestedView<T>, index: number, value: T['TValue']): void;
55-
public getChildAt<R extends DataType = DataType>(index: number) {
56-
return this._childColumns[index] || (
57-
this._childColumns[index] = Vector.create<R>(this.childData[index]));
55+
public getChildAt<R extends DataType = DataType>(index: number): Vector<R> | null {
56+
return index < 0 || index >= this.numChildren
57+
? null
58+
: (this._children[index] as Vector<R>) ||
59+
(this._children[index] = Vector.create<R>(this.childData[index]));
5860
}
5961
public *[Symbol.iterator](): IterableIterator<T['TValue']> {
6062
const get = this.getNested;
@@ -120,14 +122,22 @@ export class DenseUnionView extends UnionView<DenseUnion> {
120122

121123
export class StructView extends NestedView<Struct> {
122124
protected getNested(self: StructView, index: number) {
123-
return new RowView(self as any, self._childColumns, index);
125+
return new RowView(self as any, self._children, index);
124126
}
125127
protected setNested(self: StructView, index: number, value: any): void {
126-
let idx = -1, len = self.numChildren;
128+
let idx = -1, len = self.numChildren, child: Vector | null;
127129
if (!(value instanceof NestedView || value instanceof Vector)) {
128-
while (++idx < len) { self.getChildAt(idx).set(index, value[idx]); }
130+
while (++idx < len) {
131+
if (child = self.getChildAt(idx)) {
132+
child.set(index, value[idx]);
133+
}
134+
}
129135
} else {
130-
while (++idx < len) { self.getChildAt(idx).set(index, value.get(idx)); }
136+
while (++idx < len) {
137+
if (child = self.getChildAt(idx)) {
138+
child.set(index, value.get(idx));
139+
}
140+
}
131141
}
132142
}
133143
}
@@ -140,14 +150,22 @@ export class MapView extends NestedView<Map_> {
140150
(xs[x.name] = i) && xs || xs, Object.create(null));
141151
}
142152
protected getNested(self: MapView, index: number) {
143-
return new MapRowView(self as any, self._childColumns, index);
153+
return new MapRowView(self as any, self._children, index);
144154
}
145155
protected setNested(self: MapView, index: number, value: { [k: string]: any }): void {
146-
const typeIds = self.typeIds as any;
156+
let typeIds = self.typeIds as any, child: Vector | null;
147157
if (!(value instanceof NestedView || value instanceof Vector)) {
148-
for (const key in typeIds) { self.getChildAt(typeIds[key]).set(index, value[key]); }
158+
for (const key in typeIds) {
159+
if (child = self.getChildAt(typeIds[key])) {
160+
child.set(index, value[key]);
161+
}
162+
}
149163
} else {
150-
for (const key in typeIds) { self.getChildAt(typeIds[key]).set(index, value.get(key as any)); }
164+
for (const key in typeIds) {
165+
if (child = self.getChildAt(typeIds[key])) {
166+
child.set(index, value.get(key as any));
167+
}
168+
}
151169
}
152170
}
153171
}
@@ -160,7 +178,7 @@ export class RowView extends UnionView<SparseUnion> {
160178
this.length = data.numChildren;
161179
}
162180
public clone(data: Data<SparseUnion> & NestedView<any>): this {
163-
return new (<any> this.constructor)(data, this._childColumns, this.rowIndex) as this;
181+
return new (<any> this.constructor)(data, this._children, this.rowIndex) as this;
164182
}
165183
protected getChildValue(self: RowView, index: number, _typeIds: any, _valueOffsets?: any): any | null {
166184
const child = self.getChildAt(index);

0 commit comments

Comments
 (0)