7

整数オーバーフローを引き起こすバグがあり、間違った (負の) タイムスタンプがデータベースに書き込まれました。コードは修正済みですが、間違ったデータも修正したいです

間違った結果を取得して Integer.MAX_VALUE を追加することもできると思いましたが、うまくいかないようで、高い値が残っていました。以下のコード スニペットにoffset値がありますが、入力値は保存されません。

次のコードはバグを再現します。

@Test
public void testArexxConversion()
{
    // The input values represent seconds since midnight, Jan 1, 2000 UTC
    final int sample = 361450072; // A sample input value drawn from production
    // I use the offset from the UNIX epoch to convert the vakue to UNIX seconds
    final int offset = 946684800; // midnight, Jan 01 2000 UTC in UNIX seconds
    // This was the buggy line in my code, the assertion will fail
    long result = (sample + offset) * 1000;
    // Prints 'Result is negative: -1830153280'
    Assert.assertTrue(result > 0, String.format("Result is negative: %d", result));
    // This is for comparison
    Date dt = new Date(offset * 1000);
    Assert.assertEquals(dt.getTime() + sample * 1000, result);
}
4

3 に答える 3

5

データベースのバグを修正する方法

データベースのバグを修正するには、すべてのバグのあるデータに次の追加を行うことができます。

long new_result = old_buggy_result + 1309965025280L;

定数は次のように見つかりました。

  1. バグのresultある値を確認する
  2. 正しいresult値を見つけてください。
  3. バグのresultある値に追加して、正しい `result を見つけてください。

ただし、これは、データベースまたは他の場所に保存sampleした場合にのみ可能です。offset

それ以外の場合は、元の計算中に発生したラップの数によって異なります。

long size_of_int = (long)Math.pow(2, 32);
int number_of_wraps = 305 // Only correct in your example!
                          // You can't deduct the number of wraps from
                          // the wrong value alone, because that information
                          // is lost in the modulo (the "wrap")
long correct_number = wrong_number + size_of_int * number_of_wraps;

データベース内の数値がサンプル値に十分近い場合、これは、ラップ数として 305 を使用して上記を実行できることを意味します。

バグの説明 (将来の読者向け)

ここでの操作:

 (sample + offset) * 1000;

intはおよび ではなくを使用して計算されlongます。intしかし、結果は変数に保存するには「大きすぎます」 。そのため、オーバーフローがあります。

次のように変更します。

  ((long) sample + offset) * 1000L;

これで+*演算はlong値を使用して実行され、結果はlongオーバーフローしない値になります。

于 2011-06-15T11:19:38.820 に答える
2

それは次のようになります。

long result = ... ; // bad negative from database
long new_result = (long)((int)result - Integer.MAX_VALUE) + Integer.MAX_VALUE;
于 2011-06-15T11:50:28.600 に答える
0

この行を置き換えます。

long result = (long)(sample + offset) * 1000L;
于 2011-06-15T11:21:03.070 に答える