-
Notifications
You must be signed in to change notification settings - Fork 12.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
__builtin_object_size() does not track object sizes across assignment #55742
Comments
clang has two implementations of __builtin_objectsize: one at llvm-project/clang/lib/AST/ExprConstant.cpp Line 11705 in de20fb7
The second one is generally less powerful; we lose a lot of information. In this particular case, I'm not sure how we could even represent the information necessary in LLVM IR. So the only way I can think of to make this work with clang's current architecture is to run __builtin_objectsize through some sort of dataflow analysis on the AST. I doubt this is high enough on anyone's priority list to make it worth spending months on something like that. Maybe it becomes simpler if the project to make clang generate MLIR works out... |
Sign me up. :^) |
I've been investigating this test case, and the reason why it fails for Basically it has nothing to do with assignment, it's a problem of not being able to find the allocation point, and we decide not to rely on type information. Note that if the second argument of |
cc @gburgessiv who authored the flexible array extension. |
@llvm/issue-subscribers-clang-codegen |
I don't have the background on LLVM's design but it seems to me that the difference is due to the different decisions made by the two implementations of of the built-in. The front end folds simple expressions and seems to do no flow analysis. The middle end does flow analysis but doesn't fully consider type information. A simple test case is below (the same effect can be seen by making the array subscript a local variable set to 1):
GCC has just one implementation, in the middle end, that considers type info, so it folds both of the above to 4. |
I think @efriedma-quic covers the reasons behind this well in general. RE flexible arrays, yeah, clang's frontend gives up in many of those cases. The general pattern of code that it tries to allow for is:
Which is relatively common in C. Clang originally had checks for whether the trailing member of the struct was unsized or had a length <= 1, but that broke in the face of e.g., FreeBSD's |
I feel like most of the comments above are related to bug #55741 , which is about lacking
from: expect(__builtin_object_size(middle->c, 1), 16);
p = (void *)&middle->c[1];
expect(__builtin_object_size(p, 1), 12); This is not from flex-array confusion. (Additionally, using option "3" for |
This is mostly what I think @efriedma-quic was trying to speak to. Let me try to break down what I think is happening here (I haven't actually run Clang, so I could be wrong, but I'm relatively confident that I'm not :) ): In trying to evaluate Clang, having failed to determine the objectsize of Since LLVM fails to determine this, it lowers (*) -- If it were an |
Casts also seem problematic: struct foo {
int x;
int y [14];
};
struct quux {
long x, y, z;
};
unsigned long baz(void) {
struct foo my_foo;
return __builtin_object_size(&((struct quux*)&my_foo)->y, 1);
} GCC: 8 |
That looks like a different issue; all the relevant information is available to the code in ExprConstant, it's just coming up with an over-conservative answer. |
The information used to examine object sizes is lost across assignment:
__builtin_object_size(p, 1)
should equal 12, but instead is -1. (__bos(&instance->c[1], 1)
correctly returns 12.)This breaks
FORTIFY_SOURCE
protection as buffers that should be visible become trivially obfuscated, and is a regression compared to GCC.https://godbolt.org/z/4Pozfe9bY
The text was updated successfully, but these errors were encountered: