Skip to content

Commit a63ba18

Browse files
committed
Merge remote-tracking branch 'upstream/develop-8.1' into merge-develop_8.1_23.02.17
2 parents b211dbb + 2e92073 commit a63ba18

4 files changed

Lines changed: 224 additions & 59 deletions

File tree

buildbot.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ dist-upload-files.txt sha1sum.txt:
200200
-o -name 'LiveCode*Server-*-Windows.zip' \
201201
-o -name 'LiveCode*Docs-*.zip' \
202202
-o -name '*-bin.tar.xz' \
203+
-o -name '*-bin.tar.bz2' \
203204
> dist-upload-files.txt; \
204205
if test "${UPLOAD_RELEASE_NOTES}" = "yes"; then \
205206
find . -maxdepth 1 -name 'LiveCodeNotes*.pdf' >> dist-upload-files.txt; \

docs/lcb/notes/19214.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# LiveCode Builder Standard Library
2+
3+
## Foreign function interface
4+
5+
* When passing a Number to one of the foreign integer types (`LCInt`, `LCUInt`,
6+
`IntSize`, `UIntSize`), an error will be thrown if the value is outside the
7+
range of the requested type.
8+
9+
* The `IntSize` and `UIntSize` types can hold the full 64-bit integer range,
10+
however the maximum magnitude which is supported for converting to and from
11+
Number is 2^53. An error will be thrown for any conversions outside this
12+
range.
13+
14+
# [19214] Increase usable range of IntSize and UIntSize types

libfoundation/src/foundation-foreign.cpp

Lines changed: 88 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919

2020
#include "foundation-private.h"
2121

22+
#include <limits>
23+
2224
////////////////////////////////////////////////////////////////////////////////
2325

2426
MC_DLLEXPORT_DEF MCTypeInfoRef kMCBoolTypeInfo;
@@ -180,6 +182,15 @@ bool __MCForeignValueCopyDescription(__MCForeignValue *self, MCStringRef& r_desc
180182

181183
////////////////////////////////////////////////////////////////////////////////
182184

185+
static bool
186+
__throw_numeric_overflow(MCTypeInfoRef p_error, MCTypeInfoRef p_type)
187+
{
188+
return MCErrorCreateAndThrow(p_error,
189+
"type", p_type,
190+
"reason", MCSTR("numeric overflow"),
191+
nil);
192+
}
193+
183194
// bool foreign type handlers
184195

185196
static void __bool_finalize(void *)
@@ -329,39 +340,52 @@ __size_import (void *contents,
329340
bool release,
330341
MCValueRef & r_value)
331342
{
332-
size_t t_value = *(size_t *) contents;
343+
size_t t_value = *static_cast<size_t *>(contents);
333344

334-
if (t_value > UINTEGER_MAX)
335-
{
336-
MCErrorCreateAndThrow (kMCForeignImportErrorTypeInfo,
337-
"type", kMCSizeTypeInfo,
338-
"reason", MCSTR("too large for Number representation"),
339-
nil);
340-
return false;
345+
if (t_value <= UINTEGER_MAX)
346+
{
347+
return MCNumberCreateWithUnsignedInteger(uinteger_t(t_value),
348+
reinterpret_cast<MCNumberRef&>(r_value));
349+
}
350+
#ifdef __64_BIT__
351+
else if (t_value <= (1ULL << std::numeric_limits<double>::digits))
352+
{
353+
return MCNumberCreateWithReal(double(t_value),
354+
reinterpret_cast<MCNumberRef&>(r_value));
355+
}
356+
#endif
357+
else
358+
{
359+
return __throw_numeric_overflow(kMCForeignImportErrorTypeInfo,
360+
kMCSizeTypeInfo);
341361
}
342-
343-
return MCNumberCreateWithUnsignedInteger((uinteger_t) t_value,
344-
(MCNumberRef &) r_value);
345362
}
346363

347364
static bool
348365
__ssize_import (void *contents,
349366
bool release,
350367
MCValueRef & r_value)
351368
{
352-
ssize_t t_value = *(ssize_t *) contents;
369+
ssize_t t_value = *static_cast<ssize_t *>(contents);
353370

354-
if (t_value < INTEGER_MIN || t_value > INTEGER_MAX)
355-
{
356-
MCErrorCreateAndThrow (kMCForeignImportErrorTypeInfo,
357-
"type", kMCSizeTypeInfo,
358-
"reason", MCSTR("too large for Number representation"),
359-
nil);
360-
return false;
371+
if (t_value >= INTEGER_MIN && t_value <= INTEGER_MAX)
372+
{
373+
return MCNumberCreateWithInteger(integer_t(t_value),
374+
reinterpret_cast<MCNumberRef&>(r_value));
375+
}
376+
#ifdef __64_BIT__
377+
else if (t_value >= -(1LL << std::numeric_limits<double>::digits) &&
378+
t_value <= (1LL << std::numeric_limits<double>::digits))
379+
{
380+
return MCNumberCreateWithReal(double(t_value),
381+
reinterpret_cast<MCNumberRef&>(r_value));
382+
}
383+
#endif
384+
else
385+
{
386+
return __throw_numeric_overflow(kMCForeignImportErrorTypeInfo,
387+
kMCSSizeTypeInfo);
361388
}
362-
363-
return MCNumberCreateWithInteger((integer_t) t_value,
364-
(MCNumberRef &) r_value);
365389
}
366390

367391
static bool __float_import(void *contents, bool release, MCValueRef& r_value)
@@ -374,47 +398,64 @@ static bool __double_import(void *contents, bool release, MCValueRef& r_value)
374398
return MCNumberCreateWithReal(*(double *)contents, (MCNumberRef&)r_value);
375399
}
376400

377-
static bool __int_export(MCValueRef value, bool release, void *contents)
378-
{
379-
*(integer_t *)contents = MCNumberFetchAsInteger((MCNumberRef)value);
380-
if (release)
381-
MCValueRelease(value);
382-
return true;
383-
}
384-
385401
template <typename T>
386402
static bool
387-
__uint_export (MCValueRef value,
388-
bool release,
389-
void *contents,
390-
MCTypeInfoRef typeinfo)
391-
{
392-
/* Unsigned values can't be negative */
393-
if (0 > MCNumberFetchAsReal ((MCNumberRef) value))
394-
{
395-
MCErrorCreateAndThrow (kMCForeignExportErrorTypeInfo,
396-
"type", typeinfo,
397-
"reason", MCSTR("cannot store negative value in unsigned integer"),
398-
nil);
399-
return false;
400-
}
403+
__any_int_export(MCValueRef value,
404+
bool release,
405+
void *contents,
406+
MCTypeInfoRef typeinfo)
407+
{
408+
// Fetch the number as a double
409+
double t_value =
410+
MCNumberFetchAsReal(static_cast<MCNumberRef>(value));
411+
412+
// First check that the value is within the contiguous integer range
413+
// of doubles. If that succeeds, then check it fits within the target
414+
// integer type.
415+
if (t_value < double(-(1LL << std::numeric_limits<double>::digits)) ||
416+
t_value > double(1LL << std::numeric_limits<double>::digits) ||
417+
t_value < double(std::numeric_limits<T>::min()) ||
418+
t_value > double(std::numeric_limits<T>::max()))
419+
{
420+
return __throw_numeric_overflow(kMCForeignExportErrorTypeInfo,
421+
typeinfo);
422+
}
401423

402-
*(T *)contents = MCNumberFetchAsUnsignedInteger((MCNumberRef)value);
424+
*(T *)contents = T(t_value);
403425

404426
if (release)
405427
MCValueRelease(value);
428+
406429
return true;
407430
}
408431

432+
static bool
433+
__int_export(MCValueRef value, bool release, void *contents)
434+
{
435+
return __any_int_export<integer_t>(value, release, contents, kMCIntTypeInfo);
436+
}
437+
409438
static bool
410439
__uint_export(MCValueRef value, bool release, void *contents)
411440
{
412-
return __uint_export<uinteger_t>(value, release, contents, kMCUIntTypeInfo);
441+
return __any_int_export<uinteger_t>(value, release, contents, kMCUIntTypeInfo);
442+
}
443+
444+
static bool
445+
__size_export(MCValueRef value, bool release, void *contents)
446+
{
447+
return __any_int_export<size_t>(value, release, contents, kMCSizeTypeInfo);
448+
}
449+
450+
static bool
451+
__ssize_export(MCValueRef value, bool release, void *contents)
452+
{
453+
return __any_int_export<ssize_t>(value, release, contents, kMCSSizeTypeInfo);
413454
}
414455

415456
static bool __float_export(MCValueRef value, bool release, void *contents)
416457
{
417-
*(float *)contents = MCNumberFetchAsReal((MCNumberRef)value);
458+
*(float *)contents = float(MCNumberFetchAsReal((MCNumberRef)value));
418459
if (release)
419460
MCValueRelease(value);
420461
return true;
@@ -428,18 +469,6 @@ static bool __double_export(MCValueRef value, bool release, void *contents)
428469
return true;
429470
}
430471

431-
static bool
432-
__size_export(MCValueRef value, bool release, void *contents)
433-
{
434-
return __uint_export<size_t>(value, release, contents, kMCSizeTypeInfo);
435-
}
436-
437-
static bool
438-
__ssize_export(MCValueRef value, bool release, void *contents)
439-
{
440-
return __uint_export<ssize_t>(value, release, contents, kMCSSizeTypeInfo);
441-
}
442-
443472
static bool
444473
__bool_describe (void *contents,
445474
MCStringRef & r_string)

tests/lcb/stdlib/foreign.lcb

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ module com.livecode.foreign.tests
2020
use com.livecode.foreign
2121
use com.livecode.__INTERNAL._testlib
2222

23+
----------
24+
2325
handler TestZStringNative_Null()
2426
variable tList as ZStringNative
2527
put "\u{0}" into tList
@@ -49,4 +51,123 @@ public handler TestZStringUTF16()
4951
MCUnitTestHandlerThrows(TestZStringUTF16_Null, "ZStringUTF16 (nulls)")
5052
end handler
5153

54+
----------
55+
56+
private foreign handler printf_int(in pFormat as ZStringNative, in pValue as LCInt) returns nothing binds to "printf"
57+
private foreign handler printf_uint(in pFormat as ZStringNative, in pValue as LCUInt) returns nothing binds to "printf"
58+
private foreign handler printf_intsize(in pFormat as ZStringNative, in pValue as IntSize) returns nothing binds to "printf"
59+
private foreign handler printf_uintsize(in pFormat as ZStringNative, in pValue as UIntSize) returns nothing binds to "printf"
60+
61+
foreign handler MCHandlerTryToInvokeWithList(in Handler as any, inout Arguments as optional List, out Result as optional any) returns optional any binds to "<builtin>"
62+
63+
private handler __Is64Bit() returns nothing
64+
variable tSize as UIntSize
65+
put 4294967296.0 into tSize
66+
unsafe
67+
printf_uintsize("", tSize)
68+
end unsafe
69+
end handler
70+
71+
private handler Is64Bit()
72+
variable tResult as optional any
73+
variable tArguments as optional List
74+
variable tError as optional any
75+
put [] into tArguments
76+
unsafe
77+
put MCHandlerTryToInvokeWithList(__Is64Bit, tArguments, tResult) into tError
78+
end unsafe
79+
return tError is nothing
80+
end handler
81+
82+
handler TestIntRange_Min()
83+
variable tInt as LCInt
84+
put -2147483649.0 into tInt
85+
unsafe
86+
printf_int("", tInt)
87+
end unsafe
88+
end handler
89+
90+
handler TestIntRange_Max()
91+
variable tInt as LCInt
92+
put 2147483648.0 into tInt
93+
unsafe
94+
printf_int("", tInt)
95+
end unsafe
96+
end handler
97+
98+
handler TestUIntRange_Min()
99+
variable tUInt as LCUInt
100+
put -1.0 into tUInt
101+
unsafe
102+
printf_uint("", tUInt)
103+
end unsafe
104+
end handler
105+
106+
handler TestUIntRange_Max()
107+
variable tUInt as LCUInt
108+
put 4294967296.0 into tUInt
109+
unsafe
110+
printf_uint("", tUInt)
111+
end unsafe
112+
end handler
113+
114+
handler TestIntSizeRange_Min()
115+
variable tInt as IntSize
116+
if Is64Bit() then
117+
put -9007199254740994.0 into tInt
118+
else
119+
put -2147483649.0 into tInt
120+
end if
121+
unsafe
122+
printf_intsize("", tInt)
123+
end unsafe
124+
end handler
125+
126+
handler TestIntSizeRange_Max()
127+
variable tInt as IntSize
128+
if Is64Bit() then
129+
put 9007199254740994.0 into tInt
130+
else
131+
put 2147483648.0 into tInt
132+
end if
133+
unsafe
134+
printf_intsize("", tInt)
135+
end unsafe
136+
end handler
137+
138+
handler TestUIntSizeRange_Min()
139+
variable tUInt as UIntSize
140+
put -1.0 into tUInt
141+
unsafe
142+
printf_uintsize("", tUInt)
143+
end unsafe
144+
end handler
145+
146+
handler TestUIntSizeRange_Max()
147+
variable tUInt as UIntSize
148+
if Is64Bit() then
149+
test diagnostic "64-bit"
150+
put 9007199254740994.0 into tUInt
151+
else
152+
put 4294967296.0 into tUInt
153+
end if
154+
unsafe
155+
printf_uintsize("", tUInt)
156+
end unsafe
157+
end handler
158+
159+
public handler TestForeignIntRanges()
160+
MCUnitTestHandlerThrows(TestIntRange_Min, "LCInt minimum value")
161+
MCUnitTestHandlerThrows(TestIntRange_Max, "LCInt maximum value")
162+
163+
MCUnitTestHandlerThrows(TestUIntRange_Min, "LCUInt minimum value")
164+
MCUnitTestHandlerThrows(TestUIntRange_Max, "LCUInt maximum value")
165+
166+
MCUnitTestHandlerThrows(TestIntSizeRange_Min, "IntSize minimum value")
167+
MCUnitTestHandlerThrows(TestIntSizeRange_Max, "IntSize maximum value")
168+
169+
MCUnitTestHandlerThrows(TestUIntSizeRange_Min, "UIntSize minimum value")
170+
MCUnitTestHandlerThrows(TestUIntSizeRange_Max, "UIntSize maximum value")
171+
end handler
172+
52173
end module

0 commit comments

Comments
 (0)