给出以下代码:
std::terminate
这在GNU / Linux和Windows上运行良好,并且在最新更新到版本10.11.4之前用于在OSX上正常工作。很好,我的意思是因为没有捕获异常,Program received signal SIGSEGV, Segmentation fault.
0x0000000100000ad1 in main () at test.cpp:17
17 throw my_exception();
(gdb) bt
#0 0x0000000100000ad1 in main () at test.cpp:17
(gdb)
被调用。
但是,在使用clang(LLVM 7.3.0)的OSX 10.11.4上,程序崩溃并出现分段错误。堆栈跟踪没有帮助:
==6500== Process terminating with default action of signal 11 (SIGSEGV)
==6500== General Protection Fault
==6500== at 0x100000AD1: main (test.cpp:17)
valgrind对此也不怎么说:
throw
我认为代码不会以任何方式违反标准。我在这里错过了什么吗?
请注意,即使我在public class PingerAdapter extends BaseAdapter {
private static final String TAG = "PingerAdapter";
private final ArrayList<Pinger> mPingers;
private final LayoutInflater mLayoutInflater;
private final Context context;
public PingerAdapter(Context context) {
this(context, new ArrayList<Pinger>());
}
public PingerAdapter(Context context, ArrayList<Pinger> pingers) {
mPingers = pingers;
this.context = context;
mLayoutInflater = LayoutInflater.from(context);
}
/**
* Add a pinger to the list.
*/
public void addPinger(Pinger pinger) {
if (!mPingers.contains(pinger)) {
mPingers.add(pinger);
notifyDataSetChanged();
}
}
public void addPinger(Collection<Pinger> pingers) {
mPingers.addAll(pingers);
// When setting the list of pingers, it may be due to a ping received from another pinger.
// If there is a sending pinger, move that pinger to the top.
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
String sendingPingerToken = sharedPreferences.getString(PreferenceKeys.SENDING_PINGER_TOKEN, null);
if (sendingPingerToken != null) {
moveToTop(sendingPingerToken);
// Remove sending pinger shared preference once pinger has been moved to top.
sharedPreferences.edit().remove(PreferenceKeys.SENDING_PINGER_TOKEN).apply();
}
notifyDataSetChanged();
}
/**
* Move a pinger to the top of the list.
*/
public void moveToTop(Pinger pinger) {
mPingers.remove(pinger);
mPingers.add(0, pinger);
notifyDataSetChanged();
}
/**
* Move a pinger identified by registration token to the top of the list.
*/
public void moveToTop(String pingerToken) {
Pinger pinger = getPingerByToken(pingerToken);
if (pinger != null) {
moveToTop(pinger);
}
}
/**
* Return the pinger with matching registration token or null of no match is found.
*/
private Pinger getPingerByToken(String token) {
for (Pinger pinger: mPingers) {
if (pinger.getRegistrationToken().equals(token)) {
return pinger;
}
}
Log.e(TAG, "Pinger not found.");
return null;
}
@Override
public int getCount() {
return mPingers.size();
}
@Override
public Pinger getItem(int position) {
return mPingers.get(position);
}
@Override
public long getItemId(int position) {
return mPingers.get(position).hashCode();
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = initializeConvertView(parent);
}
final Pinger pinger = getItem(position);
Glide.with(convertView.getContext()).load(pinger.getPictureUrl()).
into((ImageView) convertView.getTag(R.id.profile_picture));
((TextView) convertView.getTag(R.id.name)).setText(pinger.getName());
return convertView;
}
private View initializeConvertView(ViewGroup parent) {
View convertView;
final View view = mLayoutInflater.inflate(R.layout.pinger_item_view, parent, false);
convertView = view;
convertView.setTag(R.id.name, view.findViewById(R.id.name));
final View tmpProfilePicture = view.findViewById(R.id.profile_picture);
// OutlineProviders are available from API 21 onwards.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
tmpProfilePicture.setClipToOutline(true);
tmpProfilePicture.setOutlineProvider(new PingerOutlineProvider());
}
convertView.setTag(R.id.profile_picture, tmpProfilePicture);
return convertView;
}
public ArrayList<Pinger> getItems() {
return mPingers;
}
}
周围添加了try-catch,代码仍会因SIGSEGV而崩溃。
答案 0 :(得分:1)
如果查看反汇编,您将看到SSE movaps
指令上发生了一般保护(GP)异常:
a.out`main: 0x100000ad0 : pushq %rbp 0x100000ad1 : movq %rsp, %rbp 0x100000ad4 : subq $0x20, %rsp 0x100000ad8 : movl $0x0, -0x4(%rbp) 0x100000adf : movl $0x10, %eax 0x100000ae4 : movl %eax, %edi 0x100000ae6 : callq 0x100000dea ; symbol stub for: __cxa_allocate_exception 0x100000aeb : movq %rax, %rdi 0x100000aee : xorps %xmm0, %xmm0 -> 0x100000af1 : movaps %xmm0, (%rax) 0x100000af4 : movq %rdi, -0x20(%rbp) 0x100000af8 : movq %rax, %rdi 0x100000afb : callq 0x100000b40 ; my_exception::my_exception ...
在my_exception :: my_exception()构造函数被调用之前,movaps
指令用于将__cxa_allocate_exception(size_t)返回的内存块清零。但是,此指针(在我的情况下为0x0000000100103498)不保证是16字节对齐。当movaps
指令的源或目标操作数是内存操作数时,操作数必须在16字节边界上对齐,否则会生成GP异常。
暂时解决问题的一种方法是在没有SSE指令的情况下进行编译(-mno-sse
)。它不是理想的解决方案,因为SSE指令可以提高性能。
我认为这与http://reviews.llvm.org/D18479:
有关r246985进行了更改以便为异常对象提供更高的对齐,理由是Itanium说_Unwind_Exception应该是&#34;双字&#34;对齐,结构通常用
__attribute__((aligned))
声明,保证16字节对齐。事实证明,libc ++ abi并没有用__attribute__((aligned))
声明结构,因此只能保证32位和64位平台上的8字节对齐。在后端发出需要16字节对齐的SIMD存储指令(例如movaps
)时,这会导致崩溃。此补丁使得ItaniumCXXABI :: getAlignmentOfExnObject在Darwin上返回8字节对齐以修复崩溃。
..哪个补丁在2016年3月31日作为r264998提交。
还有https://llvm.org/bugs/show_bug.cgi?id=24604和https://llvm.org/bugs/show_bug.cgi?id=27208似乎相关。
更新我安装了Xcode 7.3.1(昨天发布),问题似乎已修复;生成的程序集现在是:
a.out`main: 0x100000ac0 : pushq %rbp 0x100000ac1 : movq %rsp, %rbp 0x100000ac4 : subq $0x20, %rsp 0x100000ac8 : movl $0x0, -0x4(%rbp) 0x100000acf : movl $0x10, %eax 0x100000ad4 : movl %eax, %edi 0x100000ad6 : callq 0x100000dea ; symbol stub for: __cxa_allocate_exception 0x100000adb : movq %rax, %rdi 0x100000ade : movq $0x0, 0x8(%rax) 0x100000ae6 : movq $0x0, (%rax) 0x100000aed : movq %rdi, -0x20(%rbp) 0x100000af1 : movq %rax, %rdi 0x100000af4 : callq 0x100000b40 ; my_exception::my_exception ...