Skip to content

Commit

Permalink
Fix bug where parsing the rare occurence of leap-second without time…
Browse files Browse the repository at this point in the history
…-offset (#23)

* Added error checking and throwing DateTimeParseException to include the parse position where the error occurred
* Add fuzzer tests
* Fix bug where parsing the rare occurence of leap-second without time-offset in date-time would fail

---------

Co-authored-by: Morten Haraldsen <dev@ethlo.com>
  • Loading branch information
ethlo and Morten Haraldsen authored Jan 23, 2024
1 parent 10a8d67 commit 8b35415
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 4 deletions.
6 changes: 6 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ limitations under the License.
<version>5.10.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.code-intelligence</groupId>
<artifactId>jazzer-junit</artifactId>
<version>0.22.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
Expand Down
7 changes: 3 additions & 4 deletions src/main/java/com/ethlo/time/internal/EthloITU.java
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,6 @@ private static Object handleTime(int year, int month, int day, int hour, int min
if (remaining == 2)
{
final int seconds = parsePositiveInt(chars, 17, 19);
leapSecondCheck(year, month, day, hour, minute, 0, 0, null);
if (raw)
{
return new DateTime(Field.SECOND, year, month, day, hour, minute, seconds, 0, null, 0);
Expand Down Expand Up @@ -389,10 +388,10 @@ else if (c == PLUS || c == MINUS)
}

final int second = parsePositiveInt(chars, 17, 19);
leapSecondCheck(year, month, day, hour, minute, second, fractions, offset);

if (!raw)
{
leapSecondCheck(year, month, day, hour, minute, second, fractions, offset);
return OffsetDateTime.of(year, month, day, hour, minute, second, fractions, offset.toZoneOffset());
}
return fractionDigits > 0 ? DateTime.of(year, month, day, hour, minute, second, fractions, offset, fractionDigits) : DateTime.of(year, month, day, hour, minute, second, offset);
Expand All @@ -415,8 +414,8 @@ private static void leapSecondCheck(int year, int month, int day, int hour, int
final boolean isValidLeapYearMonth = leapSecondHandler.isValidLeapSecondDate(needle);
if (isValidLeapYearMonth || needle.isAfter(leapSecondHandler.getLastKnownLeapSecond()))
{
final int utcHour = hour - (offset.getTotalSeconds() / 3_600);
final int utcMinute = minute - ((offset.getTotalSeconds() % 3_600) / 60);
final int utcHour = hour - offset.getTotalSeconds() / 3_600;
final int utcMinute = minute - (offset.getTotalSeconds() % 3_600) / 60;
if (((month == Month.DECEMBER.getValue() && day == 31) || (month == Month.JUNE.getValue() && day == 30))
&& utcHour == 23
&& utcMinute == 59)
Expand Down
6 changes: 6 additions & 0 deletions src/test/java/com/ethlo/time/CorrectnessTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -470,4 +470,10 @@ void testTemporalAccessorNanos()

assertThat(parsed.getLong(ChronoField.NANO_OF_SECOND)).isEqualTo(987654321);
}

@Test
void testParseLeapSecondWhenNoTimeOffsetPresent()
{
ITU.parseLenient("3011-10-02T22:00:60.003");
}
}
42 changes: 42 additions & 0 deletions src/test/java/com/ethlo/time/fuzzer/ParseDateTimeFuzzTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.ethlo.time.fuzzer;

/*-
* #%L
* Internet Time Utility
* %%
* Copyright (C) 2017 - 2024 Morten Haraldsen (ethlo)
* %%
* Licensed 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.
* #L%
*/

import java.time.DateTimeException;

import com.code_intelligence.jazzer.api.FuzzedDataProvider;
import com.ethlo.time.ITU;

public class ParseDateTimeFuzzTest
{
@com.code_intelligence.jazzer.junit.FuzzTest(maxDuration = "2m")
void parse(FuzzedDataProvider data)
{
try
{
ITU.parseDateTime(data.consumeRemainingAsAsciiString());
}
catch (DateTimeException ignored)
{

}
}
}
51 changes: 51 additions & 0 deletions src/test/java/com/ethlo/time/fuzzer/ParseLenientFuzzTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.ethlo.time.fuzzer;

/*-
* #%L
* Internet Time Utility
* %%
* Copyright (C) 2017 - 2024 Morten Haraldsen (ethlo)
* %%
* Licensed 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.
* #L%
*/

import java.time.DateTimeException;

import com.code_intelligence.jazzer.api.FuzzedDataProvider;
import com.ethlo.time.DateTime;
import com.ethlo.time.ITU;

public class ParseLenientFuzzTest
{
@com.code_intelligence.jazzer.junit.FuzzTest(maxDuration = "2m")
void parse(FuzzedDataProvider data)
{
DateTime d = null;
try
{
d = ITU.parseLenient(data.consumeRemainingAsString());
}
catch (DateTimeException ignored)
{

}

if (d != null)
{
d.toInstant();
System.out.println(d);
d.toString();
}
}
}

0 comments on commit 8b35415

Please sign in to comment.