不要在Windows DLL内部使用函数指针进行比较!
来源:互联网 发布:ubuntu远程桌面连接 编辑:程序博客网 时间:2024/05/11 22:13
今天早晨maillist上收到如下的一封mail:
Hi folks,
I just spent somewhere between 2-3 weeks tracking down a weird bug that
resulted in our code creating corrupted files on Windows but working fine on
Linux and Mac. The issue, it turns out, affects people who allocate their
own AVPackets, and then try to use av_interleaved_write_frame on Windows.
That's because on Windows, "av_destruct_packet_nofree" outside of the libav
DLL's themselves is NOT the same as "av_destruct_packet_nofree" inside the
libav DLLs. As a result when using av_interleaved_write_frame on Windows,
packet you might think FFMPEG is copying, aren't actually duplicated and
memory corruption results.
My suggestion is to add a comment to avformat.h above
av_destruct_packet_nofree warning users in Windows to not use this method
outside of libav, and instead set AVPacket->destruct to 0 (or NULL) if they
want to manage their own packet memory. I'd like people's thoughts on that
(although at the end of this missive I put some other options that I, um,
recommend against).
Why is this happening? Read on for the gritty details of the issue:
The API doc for av_interleave_packet_per_dts suggest that setting
AVPacket->destruct to av_destruct_packet will result in the packet being
freed inside that function. Separately there is a function called
av_destruct_packet_nofree without documentation (I'm presuming if something
is in avformat.h it's meant as part of the public API). Reviewing
libavformat/utils.c, especially av_dup_packet, it suggests if you create
your own AVPacket's, and set AVPacket->destruct to
av_destruct_packet_nofree, then av_dup_packet will copy (malloc/memcpy) your
data if it needs to keep it around for writing interleaved files. All good
so far.
So here's the issue: av_destruct_packet_nofree on Windows gets exported in
the DLL with a thunking-wrapping function around it (generated by the
compiler). That means the following code:
// In External Windows executable or library that dynamically links
AVFORMAT.DLL
AVPacket pkt;
av_init_packet(&pkt);
pkt.destruct = av_destruct_packet_nofree;
AVPacket dupPkt;
dupPkt = pkt;
av_dup_packet(&dupPkt);
Will not actually successfully duplicate that packet, because
av_destruct_packet_nofree (in the windows executable linking to
AVFORMAT.DLL) != av_destruct_packet_nofree (inside AVFORMAT.DLL).
av_dup_packet explicitly checks if pkt->destruct ==
av_destruct_packet_nofree (or NULL) before deciding to copy, and in the
above code although they LOOK equal, because of Windows DLL madness,
pkt->destruct != av_destruct_packet_nofree but isn't null either. As a
result, packets you want to be duplciated are not, and craziness abounds.
Now, the fix is relatively simple in external libraries (once you determine
what's going on):
AVPacket pkt;
av_init_packet(&pkt);
pkt.destruct = 0; // set to NULL, not av_destruct_packet_nofree
AVPacket dupPkt;
dupPkt = pkt;
av_dup_packet(&dupPkt);
My proposed "fix" is to add a comment to avformat.h warning windows users
that they can't use the _nofree function and instead to set destruct to 0,
but other potential solutions:
1) Change av_dup_packet to check for != av_destruct_packet; this just swaps
the danger and could end up breaking some folks who are using the API
incorrectly in the other way so I recommend against.
2) Rework the FFMPEG build system to __dllimport and __dllexport the
appropriate functions which should fix the issue; I recommend against this
because, well, do I really need to explain why?
3) Tell all Windows users to take a long walk off a very short pier. I'm
sorely tempted to recommend this, but then 50% of my users get upset.
4) remove av_destruct_packet_nofree from avformat.h with a deprecation.
This might be the right thing to do, but I'll let the FFMPEG gods decide
that.
读完后感觉很震惊,自己之前从来没有意识到函数指针会被重新wrapper的问题!
紧接着另一个的大牛给出了如下答复:
For the record, such behaviour with respect to comparing function
addresses is in violation of the C standard.
Comparing function pointer across shared-object boundaries is undefined.
- 不要在Windows DLL内部使用函数指针进行比较!
- 不要在Windows DLL内部使用函数指针进行比较!
- setter方法的内部实现【不要在init和dealloc函数中使用accessor】
- 不要用函数的指针参数去获取函数内部的内存
- Windows使用GCC调用DLL内部的类
- delphi dll及函数指针的使用
- 千万不要返回局部对象的引用,也不要返回函数内部用new初始化的指针的引用
- 不要返回局部对象的引用,也不要返回函数内部用new初始化的指针的引用
- windows下使用nexus3进行内部maven仓库的管理
- 通过内联汇编实现DLL自卸载,即在DLL的函数内部FreeLibrary自己
- 在python 中使用 windows dll
- 在托管VC++中使用函数指针进行回调(实现回调函数功能)
- 烫烫烫烫烫烫烫----在使用指针进行字符串copy
- 使用指针类型参数和使用指针引用类型参数在函数内部用new给参数分配空间的不同结果
- 在ubuntu下使用cmake进行opencv的配置和Windows下进行使用cmake编译源代码比较,opencv3进行g++例子程序编译、动态库的制作
- 新人千万不要在 Windows 上使用 Ruby on Rails
- 新人千万不要在 Windows 上使用 Ruby on Rails
- 新人千万不要在 Windows 上使用 Ruby on Rails
- Windows2003安装vs2005和补丁时遇到1718的错误 解决方案
- OrderX订单系统发布
- 国务院原则通过电子信息产业调整振兴规划
- jQuery对select操作
- 电子商务成功案例
- 不要在Windows DLL内部使用函数指针进行比较!
- So Easy!
- 電子商務成功實例--Reebok
- jquery 小总结
- jQuery对下拉框、单选框、多选框的处理
- 堆个雪人!
- 在北大青鸟学习心得
- oracle索引分析与比较
- jQuery技巧大放送