-
Notifications
You must be signed in to change notification settings - Fork 795
fix(cambricon): clamp oversized memory request before int32 conversion #2339
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -19,6 +19,7 @@ package cambricon | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "context" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "flag" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "math" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "strings" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "testing" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "time" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -287,6 +288,44 @@ func Test_GenerateResourceRequests(t *testing.T) { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Coresreq: int32(2), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: "vmemory expressed in Gi units no longer wraps to zero", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| args: corev1.Container{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Resources: corev1.ResourceRequirements{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Limits: corev1.ResourceList{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "cambricon.com/mlu": resource.MustParse("1"), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "cambricon.com/mlu.smlu.vmemory": resource.MustParse("16Gi"), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "cambricon.com/mlu.smlu.vcore": resource.MustParse("2"), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| want: device.ContainerDeviceRequest{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Nums: int32(1), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Type: CambriconMLUDevice, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Memreq: int32(math.MaxInt32), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| MemPercentagereq: int32(0), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Coresreq: int32(2), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: "oversized plain vmemory value clamps to max int32", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| args: corev1.Container{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Resources: corev1.ResourceRequirements{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Limits: corev1.ResourceList{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "cambricon.com/mlu": resource.MustParse("1"), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "cambricon.com/mlu.smlu.vmemory": resource.MustParse("10000000"), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "cambricon.com/mlu.smlu.vcore": resource.MustParse("2"), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| want: device.ContainerDeviceRequest{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Nums: int32(1), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Type: CambriconMLUDevice, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Memreq: int32(math.MaxInt32), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| MemPercentagereq: int32(0), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Coresreq: int32(2), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+291
to
+328
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win Add a regression case for negative memory values. These cases cover As per PR objective, negative requests must be clamped to Suggested test case {
+ name: "negative vmemory value clamps to max int32",
+ args: corev1.Container{
+ Resources: corev1.ResourceRequirements{
+ Limits: corev1.ResourceList{
+ "cambricon.com/mlu": resource.MustParse("1"),
+ "cambricon.com/mlu.smlu.vmemory": resource.MustParse("-1"),
+ "cambricon.com/mlu.smlu.vcore": resource.MustParse("2"),
+ },
+ },
+ },
+ want: device.ContainerDeviceRequest{
+ Nums: int32(1),
+ Type: CambriconMLUDevice,
+ Memreq: int32(math.MaxInt32),
+ MemPercentagereq: int32(0),
+ Coresreq: int32(2),
+ },
+ },📝 Committable suggestion
Suggested change
🧰 Tools🪛 ast-grep (0.45.0)[warning] 304-304: Narrowing a non-constant integer to a smaller fixed-width type (int8/int16/int32, uint8/uint16/uint32) can silently overflow or wrap, yielding negative or truncated values that are dangerous in size, length, or index logic. Validate the source value is within the target type's range before converting (e.g. bounds-check, or use a checked helper), and avoid narrowing untrusted or len()/parsed values. (integer-overflow-narrowing-conversion-go) [warning] 323-323: Narrowing a non-constant integer to a smaller fixed-width type (int8/int16/int32, uint8/uint16/uint32) can silently overflow or wrap, yielding negative or truncated values that are dangerous in size, length, or index logic. Validate the source value is within the target type's range before converting (e.g. bounds-check, or use a checked helper), and avoid narrowing untrusted or len()/parsed values. (integer-overflow-narrowing-conversion-go) 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for _, test := range tests { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| t.Run(test.name, func(t *testing.T) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
Repository: Project-HAMi/HAMi
Length of output: 7983
🌐 Web query:
kubernetes apimachinery resource Quantity AsInt64 negative scale MilliValue validation💡 Result:
In Kubernetes
apimachinery, theresource.Quantitytype uses a fixed-point representation to avoid floating-point errors [1]. When handlingQuantityvalues, specifically regardingAsInt64,MilliValue, and negative scales, the following behaviors and validation considerations apply: 1. Rounding and Negative Values: KubernetesQuantityoperations such asMilliValue()andScaledValue()are designed to round toward "positive infinity" (away from zero) for positive numbers and toward "negative infinity" (away from zero) for negative numbers [2]. Historically, bugs in the implementation (e.g.,scaledValue) caused some small negative values to round incorrectly toward positive infinity [2]. Recent fixes have ensured these operations correctly round away from zero for negative inputs [2]. 2. AsInt64 Behavior: TheAsInt64()method returns anint64at scale 0 [3]. It will returnfalseif the value cannot be represented as anint64(e.g., it exceedsmath.MaxInt64ormath.MinInt64) or if the conversion would result in a loss of precision (i.e., the value is fractional) [3]. 3. Validation: BecauseValue()andMilliValue()project throughint64, they can overflow if theQuantityis very large [2][4]. Validating these values by checking againstresource.MaxMilliValueis considered unreliable becauseMaxMilliValueitself is a constant that may not account for fractional quantities or the full range ofQuantity[4]. Instead, the recommended approach is to useQuantity.Cmp()to compare against a defined bound, such as theresource.MaxMilliQuantity()(introduced to provide a safe, exact bound forMilliValuechecks) [4]. 4. Negative Scales: The internalint64Amountstructure handles scales, where a negative scale (e.g.,scale = -3for milli-quantities) effectively represents fractional values [5][6]. When performing operations with these scales, the implementation ensures that quantities remain representable as fixed-point numbers [1][3]. For developers, it is critical to perform sign-aware checks (e.g.,q.Sign() >= 0) and useCmp()for bounds checking to avoid overflows and incorrect rounding behavior when working with large or negative quantities [4].Citations:
🏁 Script executed:
Repository: Project-HAMi/HAMi
Length of output: 782
🏁 Script executed:
Repository: Project-HAMi/HAMi
Length of output: 607
🌐 Web query:
k8s.io/apimachinery v0.36.3 resource Amount AsInt64 negative scale source💡 Result:
In
k8s.io/apimachinery(including version v0.36.3), theAsInt64()method onint64Amountis designed to return the amount as anint64at scale 0 [1][2]. When dealing with a negative scale, the method explicitly returns0, false[1][2]. The implementation follows this logic: 1. If the internal scale is0, it returns the value andtrue[1][2]. 2. If the internal scale isnegative(a.scale < 0), it returns0, false[1][2]. This behavior reflects that a negative scale represents fractional components (e.g., milli, micro, nano), which cannot be represented as anint64at scale 0 without potential loss of precision [1][2]. 3. If the internal scale ispositive, it usespositiveScaleInt64to calculate the result [1][2]. TheAsInt64()method on the higher-levelQuantitytype similarly uses this underlyingint64Amountlogic [3][4]. It returnsfalseif theQuantityis internally represented as a decimal (inf.Dec), or if the underlyingint64Amountcannot perform the conversion (which includes cases where the scale is negative) [3][4][5]. In contexts where rounding occurs—such as inRoundUpor when converting scaled values—the library consistently enforces "rounding away from zero" (e.g., -9 at scale 1 rounds to -10) [3][6][4][7]. While the specificAsInt64()method simply fails (returnsfalse) for negative scales, related rounding functions ensure that negative values are treated correctly by moving them further from zero [8][6][7].Citations:
🌐 Web query:
Kubernetes Quantity negative scale valid as string "10000000.0" validation validation.go MilliValue 1000💡 Result:
In Kubernetes, the Quantity type is a fixed-point representation used for resources like CPU and memory [1]. When parsing a string as a Quantity, the format allows for an optional sign ("+" or "-"), a mantissa (integer part), and optional exponents/suffixes [1]. Regarding your specific technical points: 1. Negative Scale in Quantity Logic: The internal implementation of Kubernetes quantities involves handling scales to represent fixed-point math accurately [2][1]. While string inputs can include negative numbers (e.g., "-100m"), a "negative scale" in the context of the underlying math library (like
inf.Decorresource.Scale) is an implementation detail for exponent representation [2][3]. Within the public API, "negative scale" is generally not a valid or exposed concept for users; the parser simply handles the numeric value provided [1]. Explicit validation functions, such as ValidateNonnegativeQuantity, are often used to enforce that specific resource fields remain positive, as negative values are logically invalid for most resource definitions [4]. 2. MilliValue and Validation: TheMilliValue()function is an accessor that returns the value of a quantity in millicores (or equivalent units, i.e., value * 1000) [2][5]. It is implemented asq.ScaledValue(Milli), whereMilliis defined with a scale of -3 [2]. BecauseMilliValue()performs an internal scaling operation, it can overflow anint64if the underlying quantity is extremely large [2][5]. Kubernetes code often contains warnings that callers should verify the magnitude usingValue()before callingMilliValue()if overflow is a concern, though there are ongoing discussions about improving this safety in the codebase [5]. 3. String Validation: When validating quantities in Kubernetes (e.g., via admission controllers or CEL), the standard practice is to use the nativequantity(string)parsing logic, which rejects malformed strings [6][7][8]. String values like "10000000.0" are generally parsed as valid quantities, provided they do not exceed the internal architectural limits (magnitude constraints) imposed by the library, which rounds or caps values that are too large or too precise [1]. In summary, the Quantity library handles numeric strings, including fractional ones [1]. The "negative scale" mentioned is an internal mechanism for representing decimals and exponents [2], whileMilliValueis a specific utility that requires caution regardingint64overflow [5]. Validation logic for these fields typically relies on standard parsing or explicit constraints (like checking for non-negative values) to ensure data integrity [4][6].Citations:
🌐 Web query:
kubernetes apimachinery v0.36.3 Int64Amount Scale negative AsInt64 code💡 Result:
In Kubernetes apimachinery (including v0.36.x), the
int64Amounttype uses theAsInt64()method to attempt a fast conversion of a fixed-point value into anint64at scale 0 [1][2]. When thescaleof anint64Amountis negative, theAsInt64()method explicitly returns0, false[1][2]: func (a int64Amount) AsInt64 (int64, bool) { if a.scale == 0 { return a.value, true } if a.scale < 0 { // TODO: attempt to reduce factors, although it is assumed that factors are reduced prior // to the int64Amount being created. return 0, false } return positiveScaleInt64(a.value, a.scale) } The code includes a TODO comment indicating that while the method currently returnsfalsefor negative scales, it could theoretically attempt to reduce factors; however, it assumes that factors are already reduced before theint64Amountis created [1][2]. Consequently, if a consumer encounters a negative scale, the method signals that the value cannot be represented as anint64at scale 0 without potential loss of precision or simply because the fast-path optimization does not support that transformation [1][2]. IfAsInt64()returnsfalse, callers are generally expected to use theinf.Decrepresentation of theQuantityinstead [3][4].Citations:
Handle
AsInt64()failures before falling back to percentage accounting.Negative internal scales make
AsInt64()returnfalse, so whole-number decimal quantities such as10000000.0leavememnum == 0. This makesMemPercentagereqdefault to100, causingFitto use percentage accounting instead of the clamped request. Compare theQuantitywith the intended bounds first, then convert only after the bounds check passes.🤖 Prompt for AI Agents