Re: memory management / palloc / repalloc

From: Andreas Seltenreich <seltenreich(at)gmx(dot)de>
To: Jessica Ditt <jessica(dot)ditt(at)web(dot)de>
Cc: pgsql-de-allgemein(at)postgresql(dot)org
Subject: Re: memory management / palloc / repalloc
Date: 2005-06-02 22:48:28
Message-ID: 87oeao8jer.fsf@gate450.dyndns.org
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-de-allgemein

Jessica Ditt schrob:

> ich habe einen eigenen Datentyp variabler Länge. Wenn ich nun mehrere
> dieser Datentypen hintereinander hängen möchte, habe ich das Problem, ab
> einer unbestimmten und auch variierenden Länge die Fehlermeldung
> 'server closed the connection unexpectedly' zu bekommen. (Laut Logfile
> ein segmentation fault).
>
> Über andere Mailinglistenbeiträge bin ich nun zu folgenden Erkenntnissen
> gekommen, bitte korrigiert mich, wenn ich damit falsch liege:
> palloc / repalloc geben bei einem Fehler nicht NULL zurück, höchstens
> über elog eine Fehlermeldung. Ich bekomme in meiner Funktion keine
> Fehlermeldung, aber der Speicherzugriffsfehler läßt darauf schliessen,
> dass ich auf einen nicht vorhandenen Index zugreife. Gibt es einen Weg
> den Erfolg von palloc bzw. repalloc zu überprüfen?

Hmm, wenn ich src/backend/utils/mmgr/README richtig verstehe, liefern
palloc/repalloc zwar niemals NULL zurück, aber im Fehlerfall wird ja
die ganze Transaktion mitsamt des memory contexts weggeworfen. Dein
Code bekommt also gar keine Chance mehr, den Rückgabewert irgendwie zu
verarbeiten. Dein Problem dürfte also nichts mit einem fehlgeschlagen
palloc/repalloc zu tun haben.

> Beim Schreiben in Arrays muss ich mich ja darauf verlassen, dass der
> allokierte Speicher in einem Stück vorliegt. palloc/repalloc gibt doch
> nur einen Zeiger auf zusammenhängenden Speicher zurück, oder etwa nicht?

In der hinsicht unterscheiden sie sich AFAIK nicht vom malloc und
realloc der C-Library.

> PS: Ich bin immernoch nicht in der Lage, die Funkionalität meiner shared
> objects in gdb / ddd zu debuggen.

Ja, ich denke den gdb mit Postgres zum Laufen zu bekommen hat erstmal
höchste Priorität. Ich würde mich ohne auch nicht auf C-Ebene an
Postgres wagen.

> Hat jemand zufällig einen Link, wo es für >>wirkliche dummies<<
> erklärt wird? Ich weiß auch nicht, warum sich mein Geist so dagegen
> sträubt es zu verstehen, wie man den Debugger an Postgres anhängt...
> Ich weiß, ich geh Euch auf den Keks. ;)

Durr, Links hab' ich leider keine. Ich bau' mal einen Fehler in Peter
Wullingers pgsql_hello_world.c ein, und debugge es, in der Hoffnung,
daß es dir weiterhilft:

--8<---------------cut here---------------start------------->8---
#include "postgres.h"
#include "fmgr.h"

PG_FUNCTION_INFO_V1(hello_world);
Datum
hello_world(PG_FUNCTION_ARGS)
{
int *i = 0;
elog(NOTICE, "Hello, world, fourth version!");
*i = 666;
elog(NOTICE, "I'm still alive!");
PG_RETURN_INT32(0);
}
--8<---------------cut here---------------end--------------->8---

Diesmal mit -g übersetzen!

gcc -g -W -Wall -shared -I /usr/include/postgresql/server/ -L \
/usr/lib/postgresql/lib/ pgsql_hello_world.c -o pghello.so

--8<---------------cut here---------------start------------->8---
andreas(at)athlon:/tmp$ psql scratch
Willkommen bei psql 7.4.6, dem interaktiven PostgreSQL-Terminal.

Geben Sie ein: \copyright für Urheberrechtsinformationen
\h für Hilfe über SQL-Anweisungen
\? für Hilfe über interne Anweisungen
\g oder Semikolon, um eine Anfrage auszuführen
\q um zu beenden

scratch=# CREATE OR REPLACE FUNCTION hello_world() RETURNS INTEGER LANGUAGE 'C' AS '/tmp/pghello.so', 'hello_world';
CREATE FUNCTION
scratch=# select hello_world();
NOTICE: Hello, world, fourth version!
Server beendete die Verbindung unerwartet
Das heißt wahrscheinlich, daß der Server abnormal beendete
bevor oder während die Anweisung bearbeitet wurde.
Die Verbindung zum Server wurde verloren. Versuche Reset: Fehlgeschlagen.
!> \q
--8<---------------cut here---------------end--------------->8---

Im Log:

--8<---------------cut here---------------start------------->8---
2005-06-03 00:09:20 [28100] NOTICE: Hello, world, fourth version!
2005-06-03 00:09:20 [7488] LOG: server process (PID 28100) was terminated by signal 11
2005-06-03 00:09:20 [7488] LOG: terminating any other active server processes
2005-06-03 00:09:20 [11124] WARNING: terminating connection because of crash of another server process
--8<---------------cut here---------------end--------------->8---

Soweit warst du ja schon :-)

Also eine neue Sitzung. Unsere Library wird manuell geladen, damit der
Code auch im Speicher ist, wenn wir gdb anhängen:

--8<---------------cut here---------------start------------->8---
andreas(at)athlon:/tmp$ psql scratch
Willkommen bei psql 7.4.6, dem interaktiven PostgreSQL-Terminal.

Geben Sie ein: \copyright für Urheberrechtsinformationen
\h für Hilfe über SQL-Anweisungen
\? für Hilfe über interne Anweisungen
\g oder Semikolon, um eine Anfrage auszuführen
\q um zu beenden

scratch=# load '/tmp/pghello.so';
LOAD
--8<---------------cut here---------------end--------------->8---

Mit ps nachgeschaut, welches unseres backend ist:

1 S postgres 28285 7488 0 77 0 - 4378 - 00:15 ttyp5 00:00:00 postgres: andreas scratch [local] idle

Nun den gdb in einem zweiten Terminal an das Backend anhängen:

--8<---------------cut here---------------start------------->8---
athlon:~# gdb /usr/lib/postgresql/bin/postgres 28285
gdb: Symbol `emacs_ctlx_keymap' has different size in shared object, consider re-linking
GNU gdb 2002-04-01-cvs
Copyright 2002 Free Software Foundation, Inc.
[...]
Attaching to program: /usr/lib/postgresql/bin/postgres, process 28285
[...]
Reading symbols from /tmp/pghello.so...done.
Loaded symbols for /tmp/pghello.so
0xb7d2ac8c in recv () from /lib/tls/libc.so.6
(gdb) c
Continuing.

Program received signal SIGSTOP, Stopped (signal).
0xb7d2ac8c in recv () from /lib/tls/libc.so.6
(gdb) c
Continuing.
--8<---------------cut here---------------end--------------->8---

Nun den Fehler provozieren:

--8<---------------cut here---------------start------------->8---
scratch=# select hello_world();
NOTICE: Hello, world, fourth version!
--8<---------------cut here---------------end--------------->8---

Nun zeigt uns gdb was Sache ist:

--8<---------------cut here---------------start------------->8---

Program received signal SIGSEGV, Segmentation fault.
0xb71ba87c in hello_world (fcinfo=0xbfffde10) at pgsql_hello_world.c:10
10 *i = 666;
(gdb) list
5 Datum
6 hello_world(PG_FUNCTION_ARGS)
7 {
8 int *i = 0;
9 elog(NOTICE, "Hello, world, fourth version!");
10 *i = 666;
11 elog(NOTICE, "I'm still alive!");
12 PG_RETURN_INT32(0);
13 }
(gdb) bt
#0 0xb71ba87c in hello_world (fcinfo=0xbfffde10) at pgsql_hello_world.c:10
#1 0x0810c174 in ExecMakeFunctionResult ()
#2 0x0810dd1a in ExecEvalExpr ()
#3 0x0810ea64 in ExecCleanTargetListLength ()
#4 0x0810ecca in ExecProject ()
#5 0x08116a15 in ExecResult ()
#6 0x0810abd5 in ExecProcNode ()
#7 0x0810955c in ExecEndPlan ()
#8 0x08108938 in ExecutorRun ()
#9 0x08180233 in PortalRun ()
#10 0x0817ffef in PortalRun ()
#11 0x0817c834 in pg_plan_queries ()
#12 0x0817eda0 in PostgresMain ()
#13 0x0815894b in ClosePostmasterPorts ()
#14 0x08158333 in ClosePostmasterPorts ()
#15 0x08156838 in PostmasterMain ()
#16 0x08155ec9 in PostmasterMain ()
#17 0x08125e76 in main ()
#18 0xb7c67974 in __libc_start_main () from /lib/tls/libc.so.6
--8<---------------cut here---------------end--------------->8---

Den Backtrace hab' ich hier mal nicht gekürzt, das muß man einfach
'mal gesehen haben :-)

Wir wissen also nun, daß unser Speicherzugriffsfehler in Funktion
hello_world, pgsql_hello_world.c Zeile 10 passiert ist, und bekommen
oben sogar den Quellcode angezeigt.

Viel mehr Spaß macht es, an dem lebendigen Programm zu arbeiten,
deshalb zu Lehrzwecken nochmal von vorne mit breakpoints:

Neue Sitzung:
--8<---------------cut here---------------start------------->8---
andreas(at)athlon:/tmp$ psql scratch
Willkommen bei psql 7.4.6, dem interaktiven PostgreSQL-Terminal.

Geben Sie ein: \copyright für Urheberrechtsinformationen
\h für Hilfe über SQL-Anweisungen
\? für Hilfe über interne Anweisungen
\g oder Semikolon, um eine Anfrage auszuführen
\q um zu beenden

scratch=# load '/tmp/pghello.so';
LOAD
scratch=#
--8<---------------cut here---------------end--------------->8---

Neue GDB-Sitzung:

--8<---------------cut here---------------start------------->8---
athlon:~# ps -elf|grep postgr
1 S postgres 28670 7488 0 76 0 - 4379 - 00:35 ttyp5 00:00:00 postgres: andreas scratch [local] idle
athlon:~# gdb /usr/lib/postgresql/bin/postgres 28670
[...]
Reading symbols from /tmp/pghello.so...done.
Loaded symbols for /tmp/pghello.so
0xb7d2ac8c in recv () from /lib/tls/libc.so.6
(gdb) break hello_world
Breakpoint 1 at 0xb71ba84a: file pgsql_hello_world.c, line 8.
(gdb) c
--8<---------------cut here---------------end--------------->8---

psql:
--8<---------------cut here---------------start------------->8---
scratch=# select hello_world();
--8<---------------cut here---------------end--------------->8---

gdb:
--8<---------------cut here---------------start------------->8---
Breakpoint 1, hello_world (fcinfo=0xbfffde10) at pgsql_hello_world.c:8
8 int *i = 0;
(gdb) s
9 elog(NOTICE, "Hello, world, fourth version!");
(gdb) s
10 *i = 666;
(gdb) print i
$1 = (int *) 0x0
(gdb) print i = malloc(4)
$2 = (int *) 0x830f4b8
(gdb) c
Continuing.
--8<---------------cut here---------------end--------------->8---

Und siehe da:
--8<---------------cut here---------------start------------->8---
NOTICE: Hello, world, fourth version!
NOTICE: I'm still alive!
hello_world
-------------
0
(1 Zeile)

scratch=#
--8<---------------cut here---------------end--------------->8---

HTH
Andreas

In response to

Browse pgsql-de-allgemein by date

  From Date Subject
Next Message Andreas Kretschmer 2005-06-03 06:03:13 Re: [despammed] Re: Umlaute & psql
Previous Message Markus Bertheau 2005-06-02 22:25:37 Re: Umlaute & psql