diff --git a/call_test.go b/call_test.go index 61c6223..5305508 100644 --- a/call_test.go +++ b/call_test.go @@ -21,6 +21,38 @@ func TestSizeTAndIntConversions(t *testing.T) { if got := Int(4096); got != 4096 { t.Fatalf("expected Int(4096) to be 4096, got %v", got) } + + cIntBits := cIntBitSize() + maxInt := int64(int(^uint(0) >> 1)) + minInt := -maxInt - 1 + cIntMax := int64(1)<<(cIntBits-1) - 1 + cIntMin := -cIntMax - 1 + + // Verify exact C.int boundaries for this platform. + if cIntMax <= maxInt { + got := Int(int(cIntMax)) + if int(got) != int(cIntMax) { + t.Fatalf("expected Int(%d) to be %d, got %v", cIntMax, cIntMax, got) + } + } + if cIntMin >= minInt { + got := Int(int(cIntMin)) + if int(got) != int(cIntMin) { + t.Fatalf("expected Int(%d) to be %d, got %v", cIntMin, cIntMin, got) + } + } + + // Int should panic when value is outside C.int range. + if cIntMax < maxInt { + assertPanics(t, "value exceeds C.int range", func() { + _ = Int(int(cIntMax + 1)) + }) + } + if cIntMin > minInt { + assertPanics(t, "value exceeds C.int range", func() { + _ = Int(int(cIntMin - 1)) + }) + } } func TestCallWrapsZeroAndNonZeroReturns(t *testing.T) { diff --git a/string_conversion.go b/string_conversion.go index 2df2ba1..5a556d5 100644 --- a/string_conversion.go +++ b/string_conversion.go @@ -73,12 +73,22 @@ func SizeT(value int) C.size_t { // // rc := cgo.Int(returnCode) func Int(value int) C.int { - if value < -2147483648 || value > 2147483647 { - panic("cgo.Int: value exceeds C.int range") + cIntBits := cIntBitSize() + if cIntBits < strconv.IntSize { + maxValue := (int64(1) << (cIntBits - 1)) - 1 + minValue := -maxValue - 1 + casted := int64(value) + if casted < minValue || casted > maxValue { + panic("cgo.Int: value exceeds C.int range") + } } return C.int(value) } +func cIntBitSize() int { + return int(unsafe.Sizeof(C.int(0)) * 8) +} + // Call invokes a C function pointer and maps a non-zero return into a Go error. // // err := cgo.Call(unsafe.Pointer(C.some_function), cgo.SizeT(len(data)))