Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.92) (envelope-from ) id 1jBzOm-0002dv-HH for pgsql-hackers@arkaria.postgresql.org; Wed, 11 Mar 2020 11:19:41 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.89) (envelope-from ) id 1jBzOl-0003AP-CP for pgsql-hackers@arkaria.postgresql.org; Wed, 11 Mar 2020 11:19:39 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1jBzOk-0003AI-Rz for pgsql-hackers@lists.postgresql.org; Wed, 11 Mar 2020 11:19:39 +0000 Received: from mail-yw1-xc42.google.com ([2607:f8b0:4864:20::c42]) by makus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.92) (envelope-from ) id 1jBzOY-0001o5-AI for pgsql-hackers@postgresql.org; Wed, 11 Mar 2020 11:19:32 +0000 Received: by mail-yw1-xc42.google.com with SMTP id c15so1593587ywn.7 for ; Wed, 11 Mar 2020 04:19:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=telsasoft-com.20150623.gappssmtp.com; s=20150623; h=date:from:to:cc:subject:message-id:references:mime-version :content-disposition:in-reply-to:user-agent; bh=fQwfndpc6WOHbHYXflrYffxT8FibCMOqFIOGBLZzozs=; b=CtXuDd3aijwRIIXTTpApWOgNqhJiFk0wK5kIz/ecW6UPWtqpwNzoWiAtNBvjQMpXRq rmBZUsfHRq4cWzkSXQ6uaDys/E2nfPT31o+gJaY3pygoLSgro/0lUSZ5JU6Rux7LH3Gc 1TRroKiCEnTkzfSedWz1KIuP6vAhaMvcULvzpW3WSxqz0C5WBrHPwWnb9LCOHD0bXG9V 0Ps+Kq75BYuQkmyNxM/FlBa+rmeJd8EGbVN+/34moEWnVXyEDLpA09sGxlsc5hhe7qPD 3NraC4T5uZJR4t1Q3MwKS+kNIoJ946Bi3lalBNRqb2a4n3WgJz+1AfUFpoIZRsUMHgZk OoyQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to:user-agent; bh=fQwfndpc6WOHbHYXflrYffxT8FibCMOqFIOGBLZzozs=; b=R7hYNSEEYuXNzauil+IPPz3s/N0MY8/VhpsFkvL5Eus50UW4XxrfdGjXCR5gjdX/cU Coz7S9m3i/GwE2ixm4i4+1MQhwIoMAWUZoUL7NY7jkRoie1Oww3eUBfOMV5Vpi7XUF9T mOqDFumzX77I0P7yri+OdLULcEmEXsuVl2tOtGYeAAzRFdCUXDG6L3N9txPa2sAuVA6d vIqVhP+xkFjPvDO+x5vwlZnEWW0ix8/EEkRxwwiLmRk8QvCbQlDPbTSXVbyDh3Y3OeYD ct8bAAuP6mVZMQ8eda/JwmbQsMuPjpoZHoDmOh36JOH4gmlV+Gcc1GPOnpTGTtkpcX+k C2lw== X-Gm-Message-State: ANhLgQ2T41E+D9UnCZj4jfw5SNGd13WPuL27WsGCWSmWXMyrXRwWbafg 3mT1ITcCmNh4JfczbfjeteHTOw== X-Google-Smtp-Source: ADFU+vs6eGft7K8f1TmAxXOW4zXXA+bJ3viuib2KAi6VCZLa2yXKwyMak2kjyjMYZDHjz9uNjpTgkQ== X-Received: by 2002:a25:e702:: with SMTP id e2mr2218368ybh.427.1583925565026; Wed, 11 Mar 2020 04:19:25 -0700 (PDT) Received: from pryzbyj (charmander.telsasoft.com. [50.244.222.1]) by smtp.gmail.com with ESMTPSA id l191sm21110940ywb.12.2020.03.11.04.19.23 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 11 Mar 2020 04:19:23 -0700 (PDT) Received: by pryzbyj (Postfix, from userid 1000) id 18CF5800C8E; Wed, 11 Mar 2020 06:19:22 -0500 (CDT) Date: Wed, 11 Mar 2020 06:19:21 -0500 From: Justin Pryzby To: Tom Lane Cc: pgsql-hackers@postgresql.org, Fabien COELHO , Alvaro Herrera , David Steele , "Bossart, Nathan" , Thomas Munro Subject: Re: pg11+: pg_ls_*dir LIMIT 1: temporary files .. not closed at end-of-transaction Message-ID: <20200311111921.GQ29065@telsasoft.com> References: <20200308173103.GC1357@telsasoft.com> <27334.1583692669@sss.pgh.pa.us> <20200308191456.GD1357@telsasoft.com> <5679.1583696409@sss.pgh.pa.us> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="FEz7ebHBGB6b2e8X" Content-Disposition: inline In-Reply-To: <5679.1583696409@sss.pgh.pa.us> User-Agent: Mutt/1.5.24 (2015-08-30) List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk --FEz7ebHBGB6b2e8X Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Sun, Mar 08, 2020 at 03:40:09PM -0400, Tom Lane wrote: > Justin Pryzby writes: > > On Sun, Mar 08, 2020 at 02:37:49PM -0400, Tom Lane wrote: > >> I guess we ought to change that function to use returns-a-tuplestore > >> protocol instead of thinking it can hold a directory open across calls. > > Thanks for the analysis. > > Do you mean it should enumerate all files during the initial SRF call, or use > > something other than the SRF_* macros ? > It has to enumerate all the files during the first call. I suppose it > I've just finished scanning the source code and concluding that all > of these functions are similarly broken: > pg_ls_dir_files I patched this one to see what it looks like and to allow /hopefully/ moving forward one way or another with the pg_ls_tmpfile() patch set (or at least avoid trying to do anything there which is too inconsistent with this fix). > I don't see anything in the documentation (either funcapi.h or > xfunc.sgml) warning that the function might not get run to completion, > either ... Also, at first glance, these seem to be passing constant "randomAccess=true" rather than (bool) (rsinfo->allowedModes&SFRM_Materialize_Random) $ git grep -wl SFRM_Materialize |xargs grep -l 'tuplestore_begin_heap(true' contrib/dblink/dblink.c contrib/pageinspect/brinfuncs.c contrib/pg_stat_statements/pg_stat_statements.c src/backend/access/transam/xlogfuncs.c src/backend/commands/event_trigger.c src/backend/commands/extension.c src/backend/foreign/foreign.c src/backend/replication/logical/launcher.c src/backend/replication/logical/logicalfuncs.c src/backend/replication/logical/origin.c src/backend/replication/slotfuncs.c src/backend/replication/walsender.c src/backend/storage/ipc/shmem.c src/backend/utils/adt/pgstatfuncs.c src/backend/utils/misc/guc.c src/backend/utils/misc/pg_config.c -- Justin --FEz7ebHBGB6b2e8X Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v1-0001-pg_ls_dir_files-avoid-leaking-DIR-if-not-run-to-c.patch" From 1fd2918d65ed8cc64158e407e56ed61b44e951db Mon Sep 17 00:00:00 2001 From: Justin Pryzby Date: Tue, 10 Mar 2020 21:01:47 -0500 Subject: [PATCH v1] pg_ls_dir_files: avoid leaking DIR if not run to completion Change to return a tuplestore rather than leaving directory open across calls. Discussion: https://www.postgresql.org/message-id/20200308173103.GC1357%40telsasoft.com See also: 9cb7db3f0 --- src/backend/utils/adt/genfile.c | 90 +++++++++++++++------------------ 1 file changed, 42 insertions(+), 48 deletions(-) diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c index 5bda2af87c..046d218ffa 100644 --- a/src/backend/utils/adt/genfile.c +++ b/src/backend/utils/adt/genfile.c @@ -527,67 +527,63 @@ pg_ls_dir_1arg(PG_FUNCTION_ARGS) static Datum pg_ls_dir_files(FunctionCallInfo fcinfo, const char *dir, bool missing_ok) { - FuncCallContext *funcctx; struct dirent *de; - directory_fctx *fctx; - - if (SRF_IS_FIRSTCALL()) - { - MemoryContext oldcontext; - TupleDesc tupdesc; + MemoryContext oldcontext; + TupleDesc tupdesc; + ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; + bool randomAccess = (rsinfo->allowedModes&SFRM_Materialize_Random) != 0; + DIR *dirdesc; + Tuplestorestate *tupstore; - funcctx = SRF_FIRSTCALL_INIT(); - oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); + if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("set-valued function called in context that cannot accept a set"))); + /* check to see if caller supports us returning a tuplestore */ + if (!(rsinfo->allowedModes & SFRM_Materialize)) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("materialize mode required, but it is not " + "allowed in this context"))); - fctx = palloc(sizeof(directory_fctx)); + /* The Tuplestore and TupleDesc should be created in ecxt_per_query_memory */ + oldcontext = MemoryContextSwitchTo(rsinfo->econtext->ecxt_per_query_memory); - tupdesc = CreateTemplateTupleDesc(3); - TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name", - TEXTOID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 2, "size", - INT8OID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 3, "modification", - TIMESTAMPTZOID, -1, 0); - funcctx->tuple_desc = BlessTupleDesc(tupdesc); + if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) + elog(ERROR, "return type must be a row type"); - fctx->location = pstrdup(dir); - fctx->dirdesc = AllocateDir(fctx->location); + tupstore = tuplestore_begin_heap(randomAccess, false, work_mem); + rsinfo->returnMode = SFRM_Materialize; + rsinfo->setResult = tupstore; + rsinfo->setDesc = tupdesc; - if (!fctx->dirdesc) - { - if (missing_ok && errno == ENOENT) - { - MemoryContextSwitchTo(oldcontext); - SRF_RETURN_DONE(funcctx); - } - else - ereport(ERROR, - (errcode_for_file_access(), - errmsg("could not open directory \"%s\": %m", - fctx->location))); - } + MemoryContextSwitchTo(oldcontext); - funcctx->user_fctx = fctx; - MemoryContextSwitchTo(oldcontext); + dirdesc = AllocateDir(dir); + if (!dirdesc) + { + if (missing_ok && errno == ENOENT) + return NULL; // XXX + else + ereport(ERROR, + (errcode_for_file_access(), + errmsg("could not open directory \"%s\": %m", + dir))); } - funcctx = SRF_PERCALL_SETUP(); - fctx = (directory_fctx *) funcctx->user_fctx; - - while ((de = ReadDir(fctx->dirdesc, fctx->location)) != NULL) + while ((de = ReadDir(dirdesc, dir)) != NULL) { Datum values[3]; - bool nulls[3]; + bool nulls[3] = {0}; char path[MAXPGPATH * 2]; struct stat attrib; - HeapTuple tuple; /* Skip hidden files */ if (de->d_name[0] == '.') continue; /* Get the file info */ - snprintf(path, sizeof(path), "%s/%s", fctx->location, de->d_name); + snprintf(path, sizeof(path), "%s/%s", dir, de->d_name); if (stat(path, &attrib) < 0) ereport(ERROR, (errcode_for_file_access(), @@ -600,14 +596,12 @@ pg_ls_dir_files(FunctionCallInfo fcinfo, const char *dir, bool missing_ok) values[0] = CStringGetTextDatum(de->d_name); values[1] = Int64GetDatum((int64) attrib.st_size); values[2] = TimestampTzGetDatum(time_t_to_timestamptz(attrib.st_mtime)); - memset(nulls, 0, sizeof(nulls)); - - tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); - SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple)); + tuplestore_putvalues(tupstore, tupdesc, values, nulls); } - FreeDir(fctx->dirdesc); - SRF_RETURN_DONE(funcctx); + tuplestore_donestoring(tupstore); + FreeDir(dirdesc); + return NULL; } /* Function to return the list of files in the log directory */ -- 2.17.0 --FEz7ebHBGB6b2e8X--