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

Lines changed: 6 additions & 0 deletions
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

Lines changed: 2 additions & 1 deletion
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

Lines changed: 64 additions & 36 deletions
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

Lines changed: 5 additions & 1 deletion
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy