Skip to content

Let GCC use the add/mul overflow intrinsics - #4929

Merged
ethomson merged 1 commit into
libgit2:masterfrom
lhchavez:fix-intrinsics
Jan 20, 2019
Merged

Let GCC use the add/mul overflow intrinsics#4929
ethomson merged 1 commit into
libgit2:masterfrom
lhchavez:fix-intrinsics

Conversation

@lhchavez

@lhchavez lhchavez commented Jan 9, 2019

Copy link
Copy Markdown
Contributor

This change tweaks the macros for git__{add,multiply}_sizet_overflow so
that GCC can use them.

It also stops using the uadd,umul versions since the add,mul can handle
way more cases.

@lhchavez lhchavez mentioned this pull request Jan 9, 2019
Comment thread src/integer.h Outdated
#if (__has_builtin(__builtin_add_overflow) || \
(defined(__GNUC__) && (__GNUC__ >= 5)))

# if (ULONG_MAX == ULLONG_MAX) && defined(_WIN64)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that I understand this - if ULONG_MAX == ULLONG_MAX, wouldn't uaddl be equivalent to uaddll?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's the intention. this means the block definitely needs some comments to explain what's going on and which cases it's addressing, will do that later today.

Comment thread src/integer.h Outdated
__builtin_uaddll_overflow(one, two, out)
# define git__multiply_sizet_overflow(out, one, two) \
__builtin_umulll_overflow(one, two, out)
# elif (ULONG_MAX == ULLONG_MAX)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that I understand this - if ULONG_MAX == ULLONG_MAX, wouldn't uaddl be equivalent to uaddll by definition?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not by definition, since unsigned long and unsigned long long are still different types to the compiler, even though they have the same size. so passing in a size_t to the wrong method results in a warning, which goes against what i'm trying to achieve.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But you're not doing anything here to validate that size_t is actually either of those types. Again, not likely but theoretically possible.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In other words, couldn't we end up in a (yes, I admit, almost certainly theoretical) situation where unsigned long and unsigned long long are both 64 bits but size_t is something shorter?

Thanks for explaining the rationale behind the uaddll vs uaddl, that makes more sense now. Some comments would indeed be helpful because this is super not obvious to me.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

err... i totally missed that case. will add that explicit check together with the comments.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's exceeeeeeeedingly unlikely to ever occur in practice. If you wanted to dust off your Cray and port libgit2 to it then it would still not have a modern compiler or 64 bit unsigned longs. But I like being a little extra paranoid when it comes to this little bit of security.

Thanks for accommodating my paranoia.

Comment thread src/integer.h
__builtin_uaddl_overflow(one, two, out)
# define git__multiply_sizet_overflow(out, one, two) \
__builtin_umull_overflow(one, two, out)
# else

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're dropping the SIZE_MAX == UINT_MAX test. I'm not sure that there's a guarantee that they're identical in the C standard. size_t is:

the unsigned integer type of the result of the sizeof operator

and is a minimum of a 16-bits. But it doesn't necessarily hold that size_t is equivalent to unsigned int that I can see in the spec. I realize that we're unlikely to encounter a system that has 16 bit size_ts and 32 bit unsigned ints, but without a strict assurance of that from the spec, since this macro is explicitly for security sensitive code, I would like to keep the explicit test.

@lhchavez lhchavez Jan 9, 2019

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what happens in the final case is that we call the __builtin_add_overflow intrinsic (as opposed to __builtin_uadd_overflow), which takes any type you give it. i just added the two other cases explicitly to make clang prefer the other two and avoid a dependency to compiler-rt.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, thanks - I had indeed read this as __builtin_uadd_overflow.

This change tweaks the macros for git__{add,multiply}_sizet_overflow so
that GCC can use them.

It also stops using the uadd,umul versions since the add,mul can handle
way more cases.
@lhchavez

Copy link
Copy Markdown
Contributor Author

All right, a nice, healthy comment explaining the whole thing has been added.

@ethomson

Copy link
Copy Markdown
Member

/rebuild

@libgit2-azure-pipelines

Copy link
Copy Markdown

Okay, @ethomson, I started to rebuild this pull request as build #1194.

@ethomson

Copy link
Copy Markdown
Member

/rebuild

@libgit2-azure-pipelines

Copy link
Copy Markdown

Okay, @ethomson, I started to rebuild this pull request as build #1225.

@ethomson

Copy link
Copy Markdown
Member

Thanks @lhchavez, while I was reviewing this, I realized that the Windows intsafe functions include this, so I added that as well. 😀

I've included your changes in #4945.

@ethomson
ethomson merged commit 2848923 into libgit2:master Jan 20, 2019
@lhchavez
lhchavez deleted the fix-intrinsics branch February 17, 2019 22:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants