深入解析Nginx的pcre库及相关注意事项

http://blog.xiuwz.com/2011/11/29/nginx-pcre-conflict/


背景:最近新开发一个Nginx扩展模块,需要结合另外一个C++库进行扩展开发,该C++库中用到了pcre库。在编译后,发现总是会core,日志中出现明显如下的错误“pcre(****) failed to get memory”。针对该C++库,单独编写额外的程序处理,则不会出现任何问题。所以问题很诡异。

针对该问题,需要了解两个方面,1、pcre库。2、nginx中pcre库的处理(编译过nginx的都支持,一般情况下nginx都依赖到了pcre)。

pcre库相关

通过学习pcre库的api:http://regexkit.sourceforge.net/Documentation/pcre/pcreapi.html

基本上了解到pcre库中会动态申请相关内存,为了保证内存的线程安全,pcre提供了以下内存管理的函数指针:

1
2
3
4
5
void *(*pcre_malloc)( size_t );
void (*pcre_free)( void *);
void *(*pcre_stack_malloc)( size_t );
void (*pcre_stack_free)( void *);
int (*pcre_callout)(pcre_callout_block *);

默认情况下,都直接采用了原生的malloc和free。

1
2
3
4
5
PCRE_EXP_DATA_DEFN void *(*pcre_malloc)( size_t ) = malloc ;
PCRE_EXP_DATA_DEFN void  (*pcre_free)( void *) = free ;
PCRE_EXP_DATA_DEFN void *(*pcre_stack_malloc)( size_t ) = malloc ;
PCRE_EXP_DATA_DEFN void  (*pcre_stack_free)( void *) = free ;
PCRE_EXP_DATA_DEFN int   (*pcre_callout)(pcre_callout_block *) = NULL;

Nginx中Pcre处理

Nginx内部对Pcre库进行了再次封装,具体在src/core/ngx_regex.c文件中。nginx_regex_*函数基本上对pcre所有的接口都进行了二次封装。其中最关键的是对内存的处理,该内存处理采用了Nginx内置的内存池概念。

具体如下,首先,重置pcre内存管理的接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void ngx_regex_init( void )
{
     pcre_malloc = ngx_regex_malloc;
     pcre_free = ngx_regex_free;
}
static void * ngx_libc_cdecl ngx_regex_malloc( size_t size)
{
     ngx_pool_t      *pool;
#if (NGX_THREADS)
     //线程相关处理
#else
     pool = ngx_pcre_pool;
#endif
     if (pool) {
         return ngx_palloc(pool, size);
     }
     return NULL;
}
static void ngx_libc_cdecl ngx_regex_free( void *p)
{
     return ;
}

然后,在需要用到的地方进行初始化调用。

1
2
3
4
5
6
7
8
9
10
11
ngx_int_t
ngx_regex_compile(ngx_regex_compile_t *rc)
{
     ...
     ngx_regex_malloc_init(rc->pool);
     re = pcre_compile(( const char *) rc->pattern.data, ( int ) rc->options,
                       &errstr, &erroff, NULL);
     /* ensure that there is no current pool */
     ngx_regex_malloc_done();
     ...
}

结论

至此,比较清楚问题是出在Nginx的pcre内存管理和第三方默认的pcre内存管理有了冲突。所以解决方案就是在调用第三方的的地方进行pcre内存函数指针重置。如下所示:

1
2
3
4
5
6
7
8
9
void *(*old_pcre_malloc)( size_t );
void (*old_pcre_free)( void *);
old_pcre_malloc = pcre_malloc;
old_pcre_free = pcre_free;
pcre_malloc = malloc ;
pcre_free = free ;
/**调用第三方库的函数接口*/
pcre_malloc = old_pcre_malloc;
pcre_free = old_pcre_free;


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值