Skip to content

Commit ea4765c

Browse files
Ruiyu Zhufacebook-github-bot
authored andcommitted
Fix potential overflow in Intp type (#197)
Summary: Pull Request resolved: #197 We use int32_t to store 32 bit signed integers. This might cause undesired behavior. To overcome this issue, we add some extra special treatment for these edge cases. Reviewed By: chualynn Differential Revision: D36106694 fbshipit-source-id: 978a021d46382857f59f43b454adeb4d7bdcbb40
1 parent 96966c1 commit ea4765c

2 files changed

Lines changed: 88 additions & 2 deletions

File tree

fbpcf/mpc_std_lib/util/Intp_impl.h

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#pragma once
99
#include <climits>
10+
#include <cmath>
1011
#include <cstdint>
1112
#include <exception>
1213
#include <type_traits>
@@ -54,7 +55,7 @@ class Intp {
5455
}
5556

5657
Intp<isSigned, width> operator+(const Intp<isSigned, width>& other) const {
57-
return Intp<isSigned, width>(round(v_ + other.v_));
58+
return Intp<isSigned, width>(add(v_, other.v_));
5859
}
5960

6061
Intp<isSigned, width> operator-() const {
@@ -70,7 +71,7 @@ class Intp {
7071
}
7172

7273
Intp<isSigned, width> operator-(const Intp<isSigned, width>& other) const {
73-
return Intp<isSigned, width>(round(v_ - other.v_));
74+
return Intp<isSigned, width>(subtract(v_, other.v_));
7475
}
7576

7677
public:
@@ -114,6 +115,42 @@ class Intp {
114115
}
115116
}
116117

118+
static NativeType add(NativeType a, NativeType b) {
119+
if constexpr (
120+
isSigned &&
121+
((width == 8) || (width == 16) || (width == 32) || (width == 64))) {
122+
// special handling is needed only for signed integer with some special
123+
// width (e.g. overflow is possible).
124+
if (std::signbit(a) == std::signbit(b)) {
125+
// the two numbers have the same sign, overflow is possible.
126+
// special treatment to prevent overflow
127+
return round(uint64_t(a) + uint64_t(b));
128+
} else {
129+
return round(a + b);
130+
}
131+
} else {
132+
return round(a + b);
133+
}
134+
}
135+
136+
static NativeType subtract(NativeType a, NativeType b) {
137+
if constexpr (
138+
isSigned &&
139+
((width == 8) || (width == 16) || (width == 32) || (width == 64))) {
140+
// special handling is needed only for signed integer with some special
141+
// width (e.g. overflow is possible).
142+
if (std::signbit(a) != std::signbit(b)) {
143+
// the two numbers have different sign, overflow is possible.
144+
// special treatment to prevent overflow
145+
return round(uint64_t(a) - uint64_t(b));
146+
} else {
147+
return round(a - b);
148+
}
149+
} else {
150+
return round(a - b);
151+
}
152+
}
153+
117154
NativeType v_;
118155
};
119156

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
#include <gmock/gmock.h>
9+
#include <gtest/gtest.h>
10+
#include <memory>
11+
#include <random>
12+
13+
#include "fbpcf/mpc_std_lib/util/util.h"
14+
15+
namespace fbpcf::mpc_std_lib::util {
16+
17+
TEST(IntpTypeTest, testAdd) {
18+
const int8_t width = 32;
19+
int64_t largestSigned = std::numeric_limits<int32_t>().max();
20+
int64_t smallestSigned = std::numeric_limits<int32_t>().min();
21+
std::random_device rd;
22+
std::mt19937_64 e(rd());
23+
std::uniform_int_distribution<int32_t> dist(smallestSigned, largestSigned);
24+
for (int i = 0; i < 1000; i++) {
25+
auto v1 = dist(e);
26+
auto v2 = dist(e);
27+
int32_t v = Intp<true, width>(v1) + Intp<true, width>(v2);
28+
int32_t expectedV = (uint64_t)v1 + (uint64_t)v2;
29+
EXPECT_EQ(v, expectedV);
30+
}
31+
}
32+
33+
TEST(IntpTypeTest, testSubtract) {
34+
const int8_t width = 32;
35+
int64_t largestSigned = std::numeric_limits<int32_t>().max();
36+
int64_t smallestSigned = std::numeric_limits<int32_t>().min();
37+
std::random_device rd;
38+
std::mt19937_64 e(rd());
39+
std::uniform_int_distribution<int32_t> dist(smallestSigned, largestSigned);
40+
for (int i = 0; i < 1000; i++) {
41+
auto v1 = dist(e);
42+
auto v2 = dist(e);
43+
int32_t v = Intp<true, width>(v1) - Intp<true, width>(v2);
44+
int32_t expectedV = (uint64_t)v1 - (uint64_t)v2;
45+
EXPECT_EQ(v, expectedV);
46+
}
47+
}
48+
49+
} // namespace fbpcf::mpc_std_lib::util

0 commit comments

Comments
 (0)