snowkit / gif

Haxe GIF encoder, implementing the NeuQuant and LZW encoding algorithms
39 stars 13 forks source link

fix out-of-bounds access #8

Closed azrafe7 closed 5 years ago

azrafe7 commented 6 years ago

Taking a closer look at the original c# lib it can be seen that in some places it first saves the value referenced by an index, and then modifies the latter (https://github.com/Chman/Moments/blob/ca6c2b10fc2b559f00c9ea6125f0d2cc8d718164/Moments%20Recorder/Scripts/Gif/NeuQuant.cs#L291-L300). Currently the haxe port could possibly try to access an out-of-bounds value. This PR aims to fix that.

azrafe7 commented 6 years ago

You can better see what I'm trying to fix by replacing the imports in NeuQuant.hx with the following code (which wraps both typedarrays with debug friendly versions):

typedef Int32Array = DebugInt32Array;
typedef UInt8Array = DebugUInt8Array;
//typedef Int32Array = haxe.io.Int32Array;
//typedef UInt8Array = haxe.io.UInt8Array;

@:forward()
@:forwardStatics()
abstract DebugInt32Array(haxe.io.Int32Array) from haxe.io.Int32Array to haxe.io.Int32Array {

  static var className = "DebugInt32Array";

  inline public function new(elements:Int) {
    trace("new " + className + "(" + elements + ")");
    this = new haxe.io.Int32Array(elements);
  }

  @:arrayAccess public inline function get(index:Int):Int {
    isWithinBounds(index);
    return this.get(index);
  }

  @:arrayAccess public inline function set(index:Int, value:Int ):Int {
    isWithinBounds(index);
    return this.set(index, value);
  }

  inline function isWithinBounds(index:Int):Bool {
    if (index < 0 || index >= this.length) throw("Invalid access at index " + index + " (should be in [0..." + this.length + "]).");
    return true;
  }
}

@:forward()
@:forwardStatics()
abstract DebugUInt8Array(haxe.io.UInt8Array) from haxe.io.UInt8Array to haxe.io.UInt8Array {

  static var className = "DebugUInt8Array";

  inline public function new(elements:Int) {
    trace("new " + className + "(" + elements + ")");
    this = new haxe.io.UInt8Array(elements);
  }

  @:arrayAccess public inline function get(index:Int):Int {
    isWithinBounds(index);
    return this.get(index);
  }

  @:arrayAccess public inline function set(index:Int, value:Int ):Int {
    isWithinBounds(index);
    return this.set(index, value);
  }

  inline function isWithinBounds(index:Int):Bool {
    if (index < 0 || index >= this.length) throw("Invalid access at index " + index + " (should be in [0..." + this.length + "]).");
    return true;
  }
}