Repository navigation
gen: widen bounded integers that do not fit into 32 bits - #180
Merged
Merged
Conversation
Collaborator
diff --git a/src/ocispec/generate.py b/src/ocispec/generate.py
index 9a06a65..d94de9a 100755
--- a/src/ocispec/generate.py
+++ b/src/ocispec/generate.py
@@ -176,12 +176,15 @@ BASIC_TYPES = (
)
-INT32_MAX = 2 ** 31 - 1
INT32_MIN = -2 ** 31
+INT32_MAX = 2 ** 31 - 1
# JSON schema files are often written with tools that serialize 2**63 as
-# 9223372036854776000 (rounded), and the image-spec itself uses that value as
-# the maximum of its own "int64" definition: treat it as in range for int64.
-INT64_MAX_ROUND = 9223372036854776000
+# 9223372036854776000 (rounded), and the image-spec itself uses such rounded
+# values as the bounds of its own "int64" and "uint64" definitions: treat
+# them as in range.
+INT64_MIN = -9223372036854776000
+INT64_MAX = 9223372036854776000
+UINT64_MAX = 18446744073709552000
def widen_integer_type(cur, typ):
@@ -190,24 +193,22 @@ def widen_integer_type(cur, typ):
declares bounds that do not fit into an int (32 bit), so that values like
a content descriptor size > 2 GiB can be parsed instead of failing with
ERANGE in common_safe_int. Integer bounds within the 32 bit range (e.g.
- schemaVersion or the runtime-spec "percent" definition) are kept as int.
+ schemaVersion or the runtime-spec "percent" definition) are kept as int,
+ and so is an integer with no bounds at all.
Interface: cur is the (already $ref resolved) schema node
History: 2026-10-12
"""
if typ != "integer":
return typ
- maximum = cur.get("maximum")
- minimum = cur.get("minimum")
- if not isinstance(maximum, (int, float)) and not isinstance(minimum, (int, float)):
+ # A missing bound does not ask for a wider type.
+ minimum = cur.get("minimum", 0)
+ maximum = cur.get("maximum", 0)
+ if INT32_MIN <= minimum and maximum <= INT32_MAX:
return typ
- fits_int64 = (not isinstance(maximum, (int, float)) or maximum <= INT64_MAX_ROUND) and \
- (not isinstance(minimum, (int, float)) or minimum >= -INT64_MAX_ROUND)
- if (isinstance(maximum, (int, float)) and (INT32_MAX < maximum <= INT64_MAX_ROUND)) or \
- (isinstance(minimum, (int, float)) and (-INT64_MAX_ROUND <= minimum < INT32_MIN)):
+ if INT64_MIN <= minimum and maximum <= INT64_MAX:
return "int64"
- if not fits_int64 and (not isinstance(minimum, (int, float)) or minimum >= 0):
- # A non-negative range that not even int64 can hold (e.g. the uint64
- # definition maximum 18446744073709552000) needs an unsigned type.
+ # Only an explicitly non-negative range may become unsigned.
+ if "minimum" in cur and minimum >= 0 and maximum <= UINT64_MAX:
return "uint64"
return typ
diff --git a/tests/data/int64_values.json b/tests/data/int64_values.json
index f8ef34e..e2278c1 100644
--- a/tests/data/int64_values.json
+++ b/tests/data/int64_values.json
@@ -17,5 +17,6 @@
"neg_two_int64": -2,
"large_integer_64bit": 73014444032,
"negative_large_integer_64bit": -73014444032,
+ "large_unsigned_integer_64bit": 18446744073709551615,
"bounded_integer_32bit": 2147483647
}
diff --git a/tests/test-15.c b/tests/test-15.c
index ee0b307..7417365 100644
--- a/tests/test-15.c
+++ b/tests/test-15.c
@@ -140,10 +140,15 @@ main ()
CHECK_INT_WIDENED_TO_INT64 (large_integer_64bit, 73014444032LL);
CHECK_INT_WIDENED_TO_INT64 (negative_large_integer_64bit, -73014444032LL);
+ /* A plain non-negative integer beyond the int64 range: widened to uint64. */
+ CHECK_UINT64 (large_unsigned_integer_64bit, UINT64_MAX);
+ CHECK_ROUNDTRIP_UINT64 (large_unsigned_integer_64bit);
+
/* A plain integer bounded to the 32 bit range stays int. */
if (data->bounded_integer_32bit != 2147483647 || data2->bounded_integer_32bit != 2147483647)
{
- printf ("bounded_integer_32bit: expected 2147483647, got %d\n", data->bounded_integer_32bit);
+ printf ("bounded_integer_32bit: expected 2147483647, got %d / %d\n",
+ data->bounded_integer_32bit, data2->bounded_integer_32bit);
exit (1);
}
diff --git a/tests/test-spec/basic/test_int64_values.json b/tests/test-spec/basic/test_int64_values.json
index f621a0f..ccf178d 100644
--- a/tests/test-spec/basic/test_int64_values.json
+++ b/tests/test-spec/basic/test_int64_values.json
@@ -60,6 +60,11 @@
"type": "integer",
"minimum": -9223372036854776000
},
+ "large_unsigned_integer_64bit": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 18446744073709552000
+ },
"bounded_integer_32bit": {
"type": "integer",
"minimum": 0, |
A property declared as a plain "integer" is always generated as int (32 bit), even when the schema bounds it to the 64 bit range. Widen the generated type instead: when the resolved schema node declares a maximum above INT32_MAX (or a minimum below INT32_MIN) map "integer" to int64. image_spec_schema_content_descriptor.size becomes int64_t, matching the type the image index element already uses for the same field. Signed-off-by: Giuseppe Scrivano <giuseppe@scrivano.org>
Member
Author
|
thanks to you and your AI friend! I've applied the diff |
kolyshkin
approved these changes
Oct 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A property declared as a plain "integer" is always generated as int (32 bit), even when the schema bounds it to the 64 bit range.
Widen the generated type instead: when the resolved schema node declares a maximum above INT32_MAX (or a minimum below INT32_MIN) map "integer" to int64.
image_spec_schema_content_descriptor.size becomes int64_t, matching the type the image index element already uses for the same field.
@kolyshkin PTAL