develooper Front page | perl.perl5.porters | Postings from May 2003

Re: Proposal: include var name in 'use of undefined value' warning

Thread Previous | Thread Next
From:
Nick Ing-Simmons
Date:
May 10, 2003 15:27
Subject:
Re: Proposal: include var name in 'use of undefined value' warning
Message ID:
20030510222650.2454.10@bactrian.ni-s.u-net.com
Dave Mitchell <davem@fdgroup.com> writes:
>Currently, code like the following produces the warning shown:
>
>    $ perl -wle 'my $x=1; my $y; print $x+$y'
>    Use of uninitialized value in addition (+) at -e line 1.
>    1
>
>When the code is more complicated, it becomes very irritating that
>Perl doesn't tell you the name of the variable that had the undef value.
>
>I include a proof-of-concept patch below (not to be applied !!!!)
>that produces the following warning instead:
>
>    Use of uninitialized variable $y in addition (+) at -e line 1.
>
>The idea is that in the case of printing out the warning when PL_op
>is valid, the children of PL_op are recursively examined to look
>for a pad/gv-type op whose varable's value is currently undefined, and if
>so, substitute the name of the var. If it can't be found, then it reverts
>to the old behaviour.
>
>Is this a good idea, and should I pursue it into a full patch?
>(The demo patch below only works for lexicals and +/-.)
>
>Any gotchas?

A. How deep do you search?  - if expression is deep and involves lots
   of closures or whatever this could take a while if 1st 100,000 
   variables are all defined.

B. IIRC geting names of pad variables at run-time is tricky - the names
   are there in compile phase.

C. Rember to fully qualify name if it is not in current package. 

>
>I suppose the biggest risk is that it gets the wrong var name - I won't
>have a feel for how likely this until I've implemented some more ops, and
>more levels or recursion.

Is this not going to get a complex as B:: stuff in the general case?


>
>Dave M.
>
>-- 
>Fire extinguisher (n) a device for holding open fire doors.
>
>
>--- sv.c-	Fri May  9 22:50:04 2003
>+++ sv.c	Fri May  9 23:20:42 2003
>@@ -562,6 +562,80 @@ Perl_sv_free_arenas(pTHX)
>     PL_sv_root = 0;
> }
> 
>+/* is the SV defined ? */
>+/* XXX lifted directly from pp_define; integrate */
>+int
>+S_isdef(pTHX_ SV* sv)
>+{
>+    if (!sv || !SvANY(sv))
>+	return 0;
>+    switch (SvTYPE(sv)) {
>+    case SVt_PVAV:
>+	if (AvMAX(sv) >= 0 || SvGMAGICAL(sv)
>+		|| (SvRMAGICAL(sv) && mg_find(sv, PERL_MAGIC_tied)))
>+	    return 1;
>+	break;
>+    case SVt_PVHV:
>+	if (HvARRAY(sv) || SvGMAGICAL(sv)
>+		|| (SvRMAGICAL(sv) && mg_find(sv, PERL_MAGIC_tied)))
>+	    return 1;
>+	break;
>+    case SVt_PVCV:
>+	if (CvROOT(sv) || CvXSUB(sv))
>+	    return 1;
>+	break;
>+    default:
>+	if (SvGMAGICAL(sv))
>+	    mg_get(sv);
>+	if (SvOK(sv))
>+	    return 1;
>+    }
>+    return 0;
>+}
>+
>+/* XXX find the name of the undefined var (if any) associated with
>+ * this op */
>+
>+SV *
>+S_find_undef_var(pTHX_ OP* o)
>+{
>+    SV* sv;
>+    if (!o)
>+	return Nullsv;
>+    switch (o->op_type) {
>+    case OP_PADSV:
>+    case OP_PADAV:
>+    case OP_PADHV:
>+	{
>+	    U32 dbseq;
>+	    CV* cv = find_runcv(&dbseq);
>+	    /* XXX this should be encapulated in pad.[ch] */
>+	    if (cv && CvPADLIST(cv)) {
>+		AV* namepad = (AV*)(*av_fetch(CvPADLIST(cv), 0, FALSE));
>+		AV* pad     = (AV*)(*av_fetch(CvPADLIST(cv), 1, FALSE));
>+		if (pad != PL_comppad)
>+		    return Nullsv;
>+		sv = *av_fetch(pad, o->op_targ, FALSE);
>+		if (S_isdef(sv))
>+		    return Nullsv;
>+		return *av_fetch(namepad, o->op_targ, FALSE);
>+	    }
>+	}
>+	return Nullsv;
>+
>+    case OP_ADD:
>+    case OP_SUBTRACT:
>+    /* XXX more binops here */
>+
>+	sv = S_find_undef_var(cBINOPx(o)->op_first);
>+	if (sv)
>+	    return sv;
>+	return S_find_undef_var(cBINOPx(o)->op_last);
>+    }
>+    return Nullsv;
>+}
>+
>+
> /*
> =for apidoc report_uninit
> 
>@@ -573,13 +647,19 @@ Print appropriate "Use of uninitialized 
> void
> Perl_report_uninit(pTHX)
> {
>-    if (PL_op)
>-	Perl_warner(aTHX_ packWARN(WARN_UNINITIALIZED), PL_warn_uninit,
>+    if (PL_op) {
>+	SV* varname = S_find_undef_var(PL_op);
>+	if (varname)
>+	    Perl_warner(aTHX_ packWARN(WARN_UNINITIALIZED),
>+		    "Use of uninitialized variable %s in %s", 
>+		    SvPV_nolen(varname), OP_DESC(PL_op));
>+	else
>+	    Perl_warner(aTHX_ packWARN(WARN_UNINITIALIZED), PL_warn_uninit,
> 		    " in ", OP_DESC(PL_op));
>+    }
>     else
> 	Perl_warner(aTHX_ packWARN(WARN_UNINITIALIZED), PL_warn_uninit, "", "");
> }
>-
> /* grab a new IV body from the free list, allocating more if necessary */
> 
> STATIC XPVIV*
-- 
Nick Ing-Simmons
http://www.ni-s.u-net.com/


Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About