|
27 | 27 |
|
28 | 28 | #include <algorithm> |
29 | 29 | #include <cctype> |
| 30 | +#include <climits> |
30 | 31 | #include <cmath> |
31 | 32 | #include <cstdlib> |
32 | 33 | #include <cstring> |
@@ -848,6 +849,44 @@ static std::string safeFormat(const char *fmt, Args... args) { |
848 | 849 | #pragma clang diagnostic pop |
849 | 850 | #endif |
850 | 851 |
|
| 852 | +// Checked signed arithmetic for the [MSBuild]::Add/Subtract/Multiply intrinsics. |
| 853 | +// Operands come straight from the (untrusted) project file, so the result can |
| 854 | +// exceed long long and the plain a+b / a-b / a*b would be signed-overflow UB. |
| 855 | +// These return false on overflow so the caller can report it instead. |
| 856 | +static bool addChecked(long long a, long long b, long long &res) { |
| 857 | + if ((b > 0 && a > LLONG_MAX - b) || (b < 0 && a < LLONG_MIN - b)) |
| 858 | + return false; |
| 859 | + res = a + b; |
| 860 | + return true; |
| 861 | +} |
| 862 | + |
| 863 | +static bool subChecked(long long a, long long b, long long &res) { |
| 864 | + if ((b < 0 && a > LLONG_MAX + b) || (b > 0 && a < LLONG_MIN + b)) |
| 865 | + return false; |
| 866 | + res = a - b; |
| 867 | + return true; |
| 868 | +} |
| 869 | + |
| 870 | +static bool mulChecked(long long a, long long b, long long &res) { |
| 871 | + if (a > 0) { |
| 872 | + if (b > 0) { |
| 873 | + if (a > LLONG_MAX / b) |
| 874 | + return false; |
| 875 | + } else if (b < LLONG_MIN / a) { |
| 876 | + return false; |
| 877 | + } |
| 878 | + } else { |
| 879 | + if (b > 0) { |
| 880 | + if (a < LLONG_MIN / b) |
| 881 | + return false; |
| 882 | + } else if (a != 0 && b < LLONG_MAX / a) { |
| 883 | + return false; |
| 884 | + } |
| 885 | + } |
| 886 | + res = a * b; |
| 887 | + return true; |
| 888 | +} |
| 889 | + |
851 | 890 | // Evaluate a $([ClassName]::Method(args)) static property function. |
852 | 891 | // Returns an empty string for unknown or unimplementable functions rather |
853 | 892 | // than throwing, so import can continue gracefully. |
@@ -893,24 +932,46 @@ std::string ImportProject::applyMSBuildStaticFunction(const std::string &classNa |
893 | 932 | if (args.size() == 2) { |
894 | 933 | long long a = 0, b = 0; |
895 | 934 | if (toInt(args[0], a) && toInt(args[1], b)) { |
896 | | - if (caseInsensitiveStringCompare(member, "Add") == 0) |
897 | | - return std::to_string(a + b); |
898 | | - if (caseInsensitiveStringCompare(member, "Subtract") == 0) |
899 | | - return std::to_string(a - b); |
900 | | - if (caseInsensitiveStringCompare(member, "Multiply") == 0) |
901 | | - return std::to_string(a * b); |
| 935 | + long long r = 0; |
| 936 | + if (caseInsensitiveStringCompare(member, "Add") == 0) { |
| 937 | + if (!addChecked(a, b, r)) { |
| 938 | + addDebug("MSBuild::Add: integer overflow"); |
| 939 | + return std::string(); |
| 940 | + } |
| 941 | + return std::to_string(r); |
| 942 | + } |
| 943 | + if (caseInsensitiveStringCompare(member, "Subtract") == 0) { |
| 944 | + if (!subChecked(a, b, r)) { |
| 945 | + addDebug("MSBuild::Subtract: integer overflow"); |
| 946 | + return std::string(); |
| 947 | + } |
| 948 | + return std::to_string(r); |
| 949 | + } |
| 950 | + if (caseInsensitiveStringCompare(member, "Multiply") == 0) { |
| 951 | + if (!mulChecked(a, b, r)) { |
| 952 | + addDebug("MSBuild::Multiply: integer overflow"); |
| 953 | + return std::string(); |
| 954 | + } |
| 955 | + return std::to_string(r); |
| 956 | + } |
902 | 957 | if (caseInsensitiveStringCompare(member, "Divide") == 0) { |
903 | 958 | if (b == 0) { |
904 | 959 | addDebug("MSBuild::Divide: division by zero"); |
905 | 960 | return std::string(); |
906 | 961 | } |
| 962 | + if (a == LLONG_MIN && b == -1) { |
| 963 | + addDebug("MSBuild::Divide: integer overflow"); |
| 964 | + return std::string(); |
| 965 | + } |
907 | 966 | return std::to_string(a / b); |
908 | 967 | } |
909 | 968 | if (caseInsensitiveStringCompare(member, "Modulo") == 0) { |
910 | 969 | if (b == 0) { |
911 | 970 | addDebug("MSBuild::Modulo: division by zero"); |
912 | 971 | return std::string(); |
913 | 972 | } |
| 973 | + if (a == LLONG_MIN && b == -1) |
| 974 | + return std::string("0"); |
914 | 975 | return std::to_string(a % b); |
915 | 976 | } |
916 | 977 | } |
|
0 commit comments