Skip to content

Commit bdcadfe

Browse files
author
Arthur Zakirov
committed
Teodor Sigaev
Fix segmentation fault. init_shared_dict() copied dictFile into info->affixFile and info->stopFile.
1 parent 62df307 commit bdcadfe

File tree

4 files changed

+77
-38
lines changed

4 files changed

+77
-38
lines changed

expected/shared_ispell.out

+6
Original file line numberDiff line numberDiff line change
@@ -211,3 +211,9 @@ SELECT ts_lexize('shared_hunspell', 'skies');
211211
{sky}
212212
(1 row)
213213

214+
SELECT ts_lexize('shared_hunspell', 'skies');
215+
ts_lexize
216+
-----------
217+
{sky}
218+
(1 row)
219+

sql/shared_ispell.sql

+2-1
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,5 @@ SELECT stop_name, words FROM shared_ispell_stoplists();
5353
SELECT shared_ispell_reset();
5454

5555
SELECT ts_lexize('shared_ispell', 'skies');
56-
SELECT ts_lexize('shared_hunspell', 'skies');
56+
SELECT ts_lexize('shared_hunspell', 'skies');
57+
SELECT ts_lexize('shared_hunspell', 'skies');

src/shared_ispell.c

+64-36
Original file line numberDiff line numberDiff line change
@@ -20,33 +20,33 @@
2020
* ===== shared segment init (postmaster startup) =====
2121
*
2222
* _PG_init
23-
* -> ispell_shmem_startup (registered as a hook)
23+
* -> ispell_shmem_startup (registered as a hook)
2424
*
2525
* ===== dictionary init (backend) =====
2626
*
2727
* dispell_init
28-
* -> init_shared_dict
29-
* -> get_shared_dict
30-
* -> NIStartBuild
31-
* -> NIImportDictionary
32-
* -> NIImportAffixes
33-
* -> NISortDictionary
34-
* -> NISortAffixes
35-
* -> NIFinishBuild
36-
* -> sizeIspellDict
37-
* -> copyIspellDict
38-
* -> copySPNode
39-
* -> get_shared_stop_list
40-
* -> readstoplist
41-
* -> copyStopList
28+
* -> init_shared_dict
29+
* -> get_shared_dict
30+
* -> NIStartBuild
31+
* -> NIImportDictionary
32+
* -> NIImportAffixes
33+
* -> NISortDictionary
34+
* -> NISortAffixes
35+
* -> NIFinishBuild
36+
* -> sizeIspellDict
37+
* -> copyIspellDict
38+
* -> copySPNode
39+
* -> get_shared_stop_list
40+
* -> readstoplist
41+
* -> copyStopList
4242
*
4343
* ===== dictionary reinit after reset (backend) =====
4444
*
4545
* dispell_lexize
46-
* -> timestamp of lookup < last reset
47-
* -> init_shared_dict
48-
* (see dispell_init above)
49-
* -> SharedNINormalizeWord
46+
* -> timestamp of lookup < last reset
47+
* -> init_shared_dict
48+
* (see dispell_init above)
49+
* -> SharedNINormalizeWord
5050
*/
5151

5252
#include "postgres.h"
@@ -166,7 +166,7 @@ _PG_fini(void)
166166
static void
167167
ispell_shmem_startup()
168168
{
169-
bool found = false;
169+
bool found = FALSE;
170170
char *segment;
171171

172172
if (prev_shmem_startup_hook)
@@ -185,6 +185,12 @@ ispell_shmem_startup()
185185
/* Was the shared memory segment already initialized? */
186186
if (!found)
187187
{
188+
if (segment == NULL) {
189+
ereport(ERROR,
190+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
191+
errmsg("Cannot acquire %d kB of shared memory",
192+
max_ispell_mem_size_kb)));
193+
}
188194
memset(segment, 0, max_ispell_mem_size());
189195

190196
#if PG_VERSION_NUM >= 90600
@@ -288,13 +294,9 @@ static void
288294
init_shared_dict(DictInfo *info, char *dictFile, char *affFile, char *stopFile)
289295
{
290296
int size;
291-
292297
SharedIspellDict *shdict = NULL;
293298
SharedStopList *shstop = NULL;
294299

295-
IspellDict *dict;
296-
StopList stoplist;
297-
298300
/* DICTIONARY + AFFIXES */
299301

300302
/* TODO This should probably check that the filenames are not NULL, and maybe that
@@ -313,6 +315,8 @@ init_shared_dict(DictInfo *info, char *dictFile, char *affFile, char *stopFile)
313315
/* load the dictionary (word list) if not yet defined */
314316
if (shdict == NULL)
315317
{
318+
IspellDict *dict;
319+
316320
dict = (IspellDict *) palloc0(sizeof(IspellDict));
317321

318322
NIStartBuild(dict);
@@ -383,6 +387,8 @@ init_shared_dict(DictInfo *info, char *dictFile, char *affFile, char *stopFile)
383387
/* load the stopwords if not yet defined */
384388
if (shstop == NULL)
385389
{
390+
StopList stoplist;
391+
386392
readstoplist(stopFile, &stoplist, lowerstr);
387393

388394
size = sizeStopList(&stoplist, stopFile);
@@ -407,11 +413,14 @@ init_shared_dict(DictInfo *info, char *dictFile, char *affFile, char *stopFile)
407413
info->lookup = GetCurrentTimestamp();
408414

409415
memcpy(info->dictFile, dictFile, strlen(dictFile) + 1);
410-
memcpy(info->affixFile, dictFile, strlen(affFile)+ 1);
416+
memcpy(info->affixFile, affFile, strlen(affFile) + 1);
411417
if (stopFile != NULL)
412-
memcpy(info->stopFile, dictFile, strlen(stopFile) + 1);
418+
memcpy(info->stopFile, stopFile, strlen(stopFile) + 1);
413419
else
414420
memset(info->stopFile, 0, sizeof(info->stopFile));
421+
422+
/* save current context as long-lived */
423+
info->saveCntx = CurrentMemoryContext;
415424
}
416425

417426
Datum dispell_init(PG_FUNCTION_ARGS);
@@ -498,6 +507,9 @@ dispell_mem_used(PG_FUNCTION_ARGS)
498507
* The StopWords parameter is optional, the two other are required.
499508
*
500509
* If any of the filenames are incorrect, the call to init_shared_dict will fail.
510+
*
511+
* Do not call it directly - it saves current memory context as long-lived
512+
* context.
501513
*/
502514
Datum
503515
dispell_init(PG_FUNCTION_ARGS)
@@ -586,7 +598,7 @@ dispell_lexize(PG_FUNCTION_ARGS)
586598
char *txt;
587599
TSLexeme *res;
588600
TSLexeme *ptr,
589-
*cptr;
601+
*cptr;
590602

591603
if (len <= 0)
592604
PG_RETURN_POINTER(NULL);
@@ -599,11 +611,27 @@ dispell_lexize(PG_FUNCTION_ARGS)
599611
/* do we need to reinit the dictionary? was the dict reset since the lookup */
600612
if (timestamp_cmp_internal(info->lookup, segment_info->lastReset) < 0)
601613
{
614+
DictInfo saveInfo = *info;
615+
MemoryContext ctx;
616+
602617
/* relock in exclusive mode */
603618
LWLockRelease(segment_info->lock);
604619
LWLockAcquire(segment_info->lock, LW_EXCLUSIVE);
605620

606-
init_shared_dict(info, info->dictFile, info->affixFile, info->stopFile);
621+
/*
622+
* info is allocated in info->saveCntx, so that's why we use a copy of
623+
* info here
624+
*/
625+
626+
MemoryContextResetAndDeleteChildren(saveInfo.saveCntx);
627+
ctx = MemoryContextSwitchTo(saveInfo.saveCntx);
628+
629+
info = palloc0(sizeof(*info));
630+
631+
init_shared_dict(info, saveInfo.dictFile,
632+
saveInfo.affixFile, saveInfo.stopFile);
633+
634+
MemoryContextSwitchTo(ctx);
607635
}
608636

609637
res = NINormalizeWord(&(info->dict), txt);
@@ -697,13 +725,13 @@ copySPNode(SPNode *node)
697725
SPNode *copy = NULL;
698726

699727
if (node == NULL)
700-
return NULL;
728+
return NULL;
701729

702730
copy = (SPNode *) shalloc(offsetof(SPNode, data) + sizeof(SPNodeData) * node->length);
703731
memcpy(copy, node, offsetof(SPNode, data) + sizeof(SPNodeData) * node->length);
704732

705733
for (i = 0; i < node->length; i++)
706-
copy->data[i].node = copySPNode(node->data[i].node);
734+
copy->data[i].node = copySPNode(node->data[i].node);
707735

708736
return copy;
709737
}
@@ -715,7 +743,7 @@ sizeSPNode(SPNode *node)
715743
int size = 0;
716744

717745
if (node == NULL)
718-
return 0;
746+
return 0;
719747

720748
size = MAXALIGN(offsetof(SPNode, data) + sizeof(SPNodeData) * node->length);
721749

@@ -815,7 +843,7 @@ sizeIspellDict(IspellDict *dict, char *dictFile, char *affixFile)
815843
/* copy affix data */
816844
size += MAXALIGN(sizeof(char *) * dict->nAffixData);
817845
for (i = 0; i < dict->nAffixData; i++)
818-
size += MAXALIGN(sizeof(char) * strlen(dict->AffixData[i]) + 1);
846+
size += MAXALIGN(sizeof(char) * strlen(dict->AffixData[i]) + 1);
819847

820848
return size;
821849
}
@@ -842,10 +870,10 @@ dispell_list_dicts(PG_FUNCTION_ARGS)
842870

843871
/* Build a tuple descriptor for our result type */
844872
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
845-
ereport(ERROR,
846-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
847-
errmsg("function returning record called in context "
848-
"that cannot accept type record")));
873+
ereport(ERROR,
874+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
875+
errmsg("function returning record called in context "
876+
"that cannot accept type record")));
849877

850878
/*
851879
* generate attribute metadata needed later to produce tuples from raw

src/shared_ispell.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#define __SHARED_ISPELL_H__
33

44
#include "storage/lwlock.h"
5+
#include "utils/memutils.h"
56
#include "utils/timestamp.h"
67
#include "tsearch/dicts/spell.h"
78
#include "tsearch/ts_public.h"
@@ -66,6 +67,9 @@ typedef struct DictInfo
6667
SharedIspellDict *shdict;
6768
IspellDict dict;
6869
SharedStopList *shstop;
70+
71+
/* MemoryContext of dict local content */
72+
MemoryContext saveCntx;
6973
} DictInfo;
7074

71-
#endif
75+
#endif

0 commit comments

Comments
 (0)