Archive for the ‘bug’ tag
my drizzle storage engine silly bug
dazuiniu is trying to write a simple plugin for drizzle, while dazuiniu always gets an error of 138 when it tries to create a table on the database. After some efforts, dazuiniu find that dazuiniu initializes the storage engine to a temporary only one, while dazuiniu created the table without specifying the ‘temporary’ syntax. To show you a little bit: here’s my initialization part:
: drizzled::plugin::StorageEngine(name_arg,
HTON_TEMPORARY_ONLY | // the bug
while on the other part, the file(drizzled/plugin/storage_engine.cc) calling the plugin has the code below:
else if (table_message.type() != message::Table::TEMPORARY &&
share.storage_engine->check_flag(HTON_BIT_TEMPORARY_ONLY) == true)
{
error= HA_ERR_UNSUPPORTED;
}
So you can see, no matter dazuiniu got the error…
cout的出错
看到 Vimer 的博客上有讲到一个有趣的 bug [1],确实是以前没有注意到的问题,很有收获。希望 Vimer 博客能再接再厉,继续写出这么优秀的文章来,特别是这种类型的文章
光看呢,还不够,大嘴牛要试着去重现这个问题,从该文的截图来看,输出到终端获得了 EPIPE 的错误信息,从而使得无法正确输出。有理由相信,这几行的片段都在一个循环里面,每次的输出的时候都会重定向标准输出的文件描述符,这个重定向可能是程序员手动做的,也可能是 CGI 框架所包含的内容。
怎么才能重现 cout 的这种一次出错之后,如果不清空 cout,那么以后的输出都会有问题的这个 bug 呢?看看大嘴牛攒出来的这个小程序,从里面输出的字符串应该可以猜出来整个流程。
#include <iostream>
using namespace std;
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int ac, char **av)
{
const char *file = "test.out";
if (ac == 2)
file = av[1];
int stdout_backup = dup(1);
int fd = open(file, O_RDWR | O_CREAT, 0644);
if (fd < 0)
{
cerr << "error opening file " << file << endl;
return -1;
}
dup2(fd, 1);
cout << "this string goes to the file." << endl;
// close the fd
close(1);
close(fd);
cout << "this would be an error." << endl;
dup2(stdout_backup, 1);
cout << "this would have gone to stdout, but due to the previous error, it fails." << endl;
cout.clear();
cout << "trying to write to stdout again. Hey! Hello Stdout Again!" << endl;
return 0;
}
cout 在被关闭文件描述符之后发生了错误,随后即使该标准输出已经被恢复,cout 仍然无法正常输出,直到大嘴牛重新清空 cout 流之后。
那么 printf 是怎么样子的呢?看看下面的程序。
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int ac, char **av)
{
const char *file = "test.out";
if (ac == 2)
file = av[1];
int stdout_backup = dup(1);
int fd = open(file, O_RDWR | O_CREAT, 0644);
if (fd < 0)
{
printf("error opening file\n");
return -1;
}
if (dup2(fd, 1) < 0)
fprintf(stderr, "error dup");
printf("this string goes to the file.\n");
fflush(stdout); /* <--- */
// close the fd
close(1);
close(fd);
printf("this would be an error.\n");
fflush(stdout); /* <--- */
dup2(stdout_backup, 1);
printf("printf is different with cout, it succeeds here.\n");
fflush(stdout); /* <--- */
return 0;
}
可以看到,当标准被关闭之后,随后的输出出现了问题,但是只要该文件描述符之后又好了,那么 printf 即又可以正常工作了。这里需要注意的一点是 fflush 的公用,如果没有这里的强制 flush,那么 printf 会放到 buffer 里面,当然前面可以加 setbuf 告诉他不要缓冲。
很有意思,大嘴牛可以重现这个问题,但是至于原文中为什么会出现这样的问题,Dante 说到有可能是底层库的问题,这个大嘴牛不敢妄言了,估计只有真正遇到了这么诡异的问题才可能知道了。呵呵
软件依赖性
有些开源软件的依赖性暴多无比,有些软件则基本没有什么依赖性。这其中有好处,也有坏处,大嘴牛就来侃侃。
好处有:
- 很多功能不需要自己实现,只需要找到实现该功能的软件库即可。
- 节约了开发的时间成本,不用自己去 reinvent the wheel。
坏处有:
- 对最终用户不友好,安装起来很麻烦,有时候某些平台上的软件版本过低,导致无法正常安装。比如 drizzle 就出现了这样的问题,大嘴牛也遇到了问题[1],下面是人家打包 RPM 时说的话[2]:
Due to a dependency on boost >= 1.38 drizzle no longer builds on RHEL 5 (boost 1.33) at the moment therefore those repositories haven’t been updated.
- 调试复杂,由于增加了依赖性,如果 bug 是发生在被以来的软件之中,那么原来使用该软件的好处就荡然无存了,出路只有两个,要么自己动手进行调试,要么像依赖的软件上报 bug,第二种情况听起来很可行,但是要知道,在开源世界中,可不是你说了最大,遇到一些比较成熟的社区那还好说,如果遇到不通情达理的,那么结果也只有两种,要么等待,漫长的等待,要么人家来一句“This’s not a bug, it’s a feature”[3][4][5]。不把你噎死才怪。
- 使用别人的软件有风险,首先需要熟悉人家的文档以及 API,另外也需要祈祷人家的 API 没有很 tricky 的东西才行,否则怎么死的都不知道。
说了一些,好像又没说什么。呵呵
[1]. http://www.dazuiniu.com/blog/2010/06/04/install-boost-trunk-version.html
[2]. https://lists.launchpad.net/drizzle-discuss/msg06747.html
[3]. http://en.wikipedia.org/wiki/Undocumented_feature
[4]. http://en.wikipedia.org/wiki/Computer_bug
[5]. http://www.codinghorror.com/blog/2008/11/thats-not-a-bug-its-a-feature-request.html