Skip to content

Commit 640f4e2

Browse files
ManishearthV8-internal LUCI CQ
authored andcommitted
[temporal] Improve timezone generation
This adds more robust timezone object generation to createTemporalFieldsObject, and also adds a ValueGenerator for timezones. We'll be more efficient if we actually test with real timezones Bug: 439921647 Change-Id: I6a6a69642519f74806a9bea1780a24be1f9d57c2 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8583094 Commit-Queue: Manish Goregaokar <manishearth@google.com> Reviewed-by: Matthias Liedtke <mliedtke@google.com>
1 parent 68a3a36 commit 640f4e2

3 files changed

Lines changed: 77 additions & 23 deletions

File tree

Sources/Fuzzilli/Base/ProgramBuilder.swift

Lines changed: 66 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
import Foundation
16+
1517
/// Builds programs.
1618
///
1719
/// This provides methods for constructing and appending random
@@ -4435,6 +4437,24 @@ public class ProgramBuilder {
44354437
return createObject(with: properties)
44364438
}
44374439

4440+
fileprivate static let allTimeZoneAbbreviations: [String] = Array(TimeZone.abbreviationDictionary.keys)
4441+
4442+
// Generate a random time zone identifier
4443+
@discardableResult
4444+
func randomTimeZone() -> Variable {
4445+
// Bias towards knownTimeZoneIdentifiers since it's a larger array
4446+
if probability(0.7) {
4447+
return loadString(chooseUniform(from: TimeZone.knownTimeZoneIdentifiers))
4448+
} else {
4449+
return loadString(chooseUniform(from: ProgramBuilder.allTimeZoneAbbreviations))
4450+
}
4451+
}
4452+
4453+
@discardableResult
4454+
func randomUTCOffset() -> Variable {
4455+
return loadString(randomUTCOffsetString(mayHaveSeconds: true))
4456+
}
4457+
44384458
// Generate an object with fields from
44394459
// https://tc39.es/proposal-temporal/#table-temporal-calendar-fields-record-fields
44404460
//
@@ -4549,32 +4569,37 @@ public class ProgramBuilder {
45494569
}
45504570
// timeZone
45514571
if zonedFields {
4552-
// TODO: write generator for timezone strings
4572+
var generatedOffset: Variable? = nil
4573+
// ZonedDateTime must be constructed with a timeZone property.
4574+
// but ZonedDateTime.with will always reject a timeZone.
4575+
//
4576+
// This is because ZonedDateTime.with is about partially replacing
4577+
// calendar fields: and operations like "change the day and also the
4578+
// time zone" are ambiguous based on whether you change the day first
4579+
// or the time zone first (and it's not a *useful* ambiguity).
4580+
// Instead, you are expected to use `.with()` and `.withTimeZone()`
4581+
// in whatever order you need.
45534582
if (!forWith) {
4554-
// ZonedDateTime needs a timeZone property
4555-
properties["timeZone"] = randomVariable(forUseAs: .string)
4583+
if Bool.random() {
4584+
// Time zones can be offsets, but cannot have seconds
4585+
generatedOffset = loadString(randomUTCOffsetString(mayHaveSeconds: false))
4586+
properties["timeZone"] = generatedOffset
4587+
} else {
4588+
properties["timeZone"] = randomTimeZone()
4589+
}
45564590
}
45574591

4558-
// Most of the time this will cause uninteresting errors
4559-
// (it needs to match with the offset), so
4560-
// we generate this with a lower probability
4561-
if probability(0.3) {
4562-
let hours = Int.random(in: 0..<24)
4563-
let minutes = Int.random(in: 0..<60)
4564-
let plusminus = Bool.random() ? "+" : "-";
4565-
var offset = String(format: "%s%02d:%02d", plusminus, hours, minutes)
4566-
if probability(0.3) {
4567-
offset += ":"
4568-
let seconds = Int.random(in: 0..<60)
4569-
offset += "\(seconds)"
4570-
if probability(0.3) {
4571-
offset += "."
4572-
offset += String(format: "%09d", Int.random(in: 0...999999999))
4573-
}
4574-
4575-
offset += ""
4576-
}
4577-
properties["offset"] = loadString(offset)
4592+
// Most of the time mixing a random offset and timezone
4593+
// will cause uninteresting errors since they need to match.
4594+
// If our timezone was a UTC offset, then there's not much harm
4595+
// in setting the field (it matches!), but otherwise we should generate offsets
4596+
// with a low probability.
4597+
if generatedOffset != nil && Bool.random() {
4598+
// Half the time when we've generated an offset, set the offset field too, it won't clash.
4599+
properties["offset"] = generatedOffset!
4600+
} else if probability(0.3) {
4601+
// Otherwise, with a low probability, generate a random offset.
4602+
properties["offset"] = loadString(randomUTCOffsetString(mayHaveSeconds: true))
45784603
}
45794604
}
45804605
return createObject(with: properties)
@@ -4725,3 +4750,21 @@ public class ProgramBuilder {
47254750

47264751
}
47274752

4753+
4754+
4755+
fileprivate func randomUTCOffsetString(mayHaveSeconds: Bool) -> String {
4756+
let hours = Int.random(in: 0..<24)
4757+
// Bias towards zero minutes since that's what most time zones do.
4758+
let zeroMinutes = probability(0.8)
4759+
let minutes = zeroMinutes ? 0 : Int.random(in: 0..<60)
4760+
let plusminus = Bool.random() ? "+" : "-";
4761+
var offset = String(format: "%@%02d:%02d", plusminus, hours, minutes)
4762+
if !zeroMinutes && mayHaveSeconds && probability(0.3) {
4763+
let seconds = Int.random(in: 0..<60)
4764+
offset = String(format: "%@:%02d", offset, seconds)
4765+
if probability(0.3) {
4766+
offset = String(format: "%@:.%09d", offset, Int.random(in: 0...999999999))
4767+
}
4768+
}
4769+
return offset
4770+
}

Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ public let codeGeneratorWeights = [
3535
"ObjectConstructorGenerator": 10,
3636
"ClassDefinitionGenerator": 20,
3737
"TrivialFunctionGenerator": 10,
38+
"TimeZoneIdGenerator": 5,
3839

3940
// Regular code generators.
4041
"ThisGenerator": 3,

Sources/Fuzzilli/CodeGen/CodeGenerators.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,16 @@ public let CodeGenerators: [CodeGenerator] = [
354354
}
355355
},
356356

357+
ValueGenerator("TimeZoneIdGenerator") { b, n in
358+
for _ in 0..<n {
359+
if Bool.random() {
360+
b.randomTimeZone()
361+
} else {
362+
b.randomUTCOffset()
363+
}
364+
}
365+
},
366+
357367
//
358368
// "Regular" Code Generators.
359369
//

0 commit comments

Comments
 (0)