Is there any way to detect an environment variable change DURING the execution of a Tcl script (I use Tk so the execution can be long) ?
For instance, if I define an environment variable MYVAR=1, then I can access it from Tcl by writing $ENV(MYVAR). Let's say now that during the execution of the Tcl program, I switch MYVAR to 2. Is there a way, or maybe a command, that scans every environment variable again so I can get 2 when I call $ENV(MYVAR) ?
First off, other processes will not see changes to the environment variables of any process. Children get a copy of the current environment when they are created, and that's it.
Secondly, to see a change in the environment variables, put a trace on the ::env variable (but tracing an individual variable is not recommended). I can't remember if this works reliably between threads, but within a thread it's pretty good provided you don't have C code modifying the variables behind your back.
proc detectChange {name1 name2 op} {
# We know what name1 and op are in this case; I'll ignore them
if {$name2 eq "MYVAR"} {
puts "MYVAR changed to $::env(MYVAR)"
}
}
trace add variable ::env write detectChange
Note that Tk internally uses traces a lot (but the C API for them, not the Tcl language API for them).
Related
ruby has some environment variables to configure garbage collection.
However, I do not know that the environment variables really have affected to ruby run-time.
How do I confirm them?
In my understanding, GC.stats show statistics but it does not show and correspond to environment variable values.
My purpose is to activate GC more frequently that means I want to reduce memory usage.
module GC
https://docs.ruby-lang.org/en/2.3.0/GC.html
e.g)
RUBY_GC_HEAP_INIT_SLOTS
RUBY_GC_HEAP_FREE_SLOTS
RUBY_GC_HEAP_GROWTH_FACTOR
RUBY_GC_HEAP_GROWTH_MAX_SLOTS
RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR
RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR
RUBY_GC_MALLOC_LIMIT
RUBY_GC_MALLOC_LIMIT_MAX
RUBY_GC_MALLOC_LIMIT_GROWTH_FACTOR
RUBY_GC_OLDMALLOC_LIMIT
RUBY_GC_OLDMALLOC_LIMIT_MAX
RUBY_GC_OLDMALLOC_LIMIT_GROWTH_FACTOR
You can inspect ENV in the running process.
Beyond that, I don't know how you would verify that the env vars you set actually did anything.
Everybody knows that variables in Lua, if not explicitly defined as "local", will be global. This will sometimes cause problems, like overriding library functions, or unexpectedly providing a value for another global variable with the same name. So it should be very helpful if there's a way to find all global variables that is defined in a single Lua code file.
However, I failed to find any clue on this seemingly quite-popular problem. The best answer I can get online is using _G to print all global variables in the environment, which isn't of much help. I'm currently coding Lua in Intellij Idea with Emmylua, a powerful tool that can show global variables in a special style, and it can easily trace a global variable to its definition; but when the code becomes quite long, this will not help much either.
So basically, I just want to get a list of global variables defined in a given Lua code file. Either with a tool or with a wonderful function. If it can make things easier, we may presume the code file is a module. If it can further print the definition locations for these global variables, that's even better. Can somebody help me?
Lua doesn't have a way to tell when or where a global was introduced.
In the special that the value is a function, debug.getinfo may be able to help by telling you where the function is defined (which is often but not always the same place where the function is made global).
You can capture the needed information at the time the global is introduced. This can be done by setting a metatable with a __newindex method on the global table. This method will be called when a new global is introduced (but not when an existing global is overridden). In this method, you can figure out where the caller came from with debug.getinfo. Also beware, if any of your other code is trying to use a metatable on the global environment, you must play nicely with it. (It can only have one metatable.)
You can also avoid using the global table. One in-between way of doing this is to override the environment. In Lua 5.2 and Lua 5.3, this is done by declaring a local table called _ENV -- all accesses to the global table will instead access this table. (Actually, global accesses always use _ENV and _ENV is _G by default.) You can make this mostly invisible by giving this _ENV a metatable that forwards accesses to _G (or whatever other environment). The difference here is that __newindex will still be called even if a binding exists in _G, so this method can detect overrides.
Using _ENV, though is inherently local to a scope (e.g. each file needs to override it). Such a hook could be installed globally as well though. If you load your modules manually with the load function (unlikely), you can just supply a custom _ENV as an argument. If you use require, it is possible to get a hold of the loaded file before it is executed by overriding (or monkey patching) the Lua searcher in package.searchers[2]. This is the built-in function that require calls to find the file in your filesystem and then load it. The return value is the loaded function which require then runs. So, after it is loaded but before it is returned back to require, you could use debug.setupvalue to override the default _ENV value (if any).
Example code (only lightly tested):
local global_info = {}
local default_searcher2 = package.searchers[2]
package.searchers[2] = function(...)
local result = default_searcher2(...)
local parent_environment = _G
local my_env = setmetatable({}, {
__index = parent_environment,
__newindex = function(self, k, v)
local new_info = debug.getinfo(2)
-- keeping rich data like this could be a memory leak
-- if some globals are assigned repeatedly, but that
-- may still be okay in a debugging scenario
local history = global_info[k]
if history == nil then
history = {}
global_info[k] = history
end
table.insert(history, {info = new_info, value = v})
parent_environment[k] = v
end,
})
if type(result) == "function" then
debug.setupvalue(result, 1, my_env)
end
return result
end
function gethistory(name)
local history = global_info[name]
if history == nil then
print('"' .. name .. '" has never been defined...')
else
print('History for "' .. name .. '":')
for _, record in ipairs(history) do
print(record.info.short_src .. ": " .. record.info.currentline)
end
end
end
Note that the hook here will only apply to files required after this code has been run, and basically only applies to Lua files (not C libs) that get included via the built-in require. It doesn't set a metatable on the global environment, so not conflict there, but it could be circumvented if files access _G directly (or e.g. setup access to _G instead of _ENV in their own _ENV tables). Such things can also be accounted for, but it can be a rabbit hole depending on how "invisible" you need this patch to be.
In Lua 5.1, instead of _ENV, you have setfenv which I believe can be used to similar effect.
Also note that all the methods I'm outlining can only detect global accesses that actually get executed at runtime.
Yes. Local versus global is a binding issue, which is primarily established at compile-time. Setting a variable is, of course, well-determined at compile-time.
Lua provides the luac compiler, which takes the argument -l for list.
In Lua 5.1, there is the opcode SETGLOBAL. A column indicates the line number of the statement and the comment indicates the name of the global.
In 5.2 and later, there is the opcode SETTABUP. A column indicates the line number of the statement and the comment indicates the name of the table and key. "Globals" are in the table referenced by the _ENV upvalue.
So, you can easily find the line number of any statement that sets a global variable with the tools Lua provides.
BTW—under many module systems, a module script would not set any global variables.
It is my understanding that when invoking spawn "string command" in xmonad, the argument "string command" is actually passed to /bin/sh.
Is there a way to change this behavior ?
More specifically, is it possible to make the instance of the interpreter called by spawn aware of some predefined environment variables (typically, SSH_AUTH_SOCK and SSH_AGENT_PID)?
Of course, it is always possible to resort to spawn "$VARIABLE=stuff; export $VARIABLE; string command", but it bothers me that the variabe should be created and exported each time.
Strictly answering your first question, the safeSpawn function in XMonad.Util.Run (in xmonad-contrib) will run a command without passing it to a shell.
However, that shouldn't make much of a difference as far as environment variables are concerned. In both cases, the spawned command should inherit the environment of the XMonad process (which the shell's startup/rc files could tweak in the case of spawn).
It's possible to set the environment of the started process with general Haskell facilities, e.g. System.Posix.Process.executeFile (and System.Environment.getEnvironment if you want to make a modified copy of the XMonad process' environment).
I write a C program gets in an environment variable's name and print out it's memory address, simply use the getenv() function to do the job. Let's say I wanna have the address location of PATH --> ./test PATH. But when I debug that program in gdb, the memory location of that variable is different. Can you explain in detail why is there such a different?
To be more exact:
./test PATH --> 0xbffffd96
debug in gdb --> 0xbffffd53
[edit] Thanks for your explanations. What I actually in question about is, how the memory address of a variable (in this case, an environment variable) changes with different programs. For example, I have 2 program a.out and b.out
./a.out --> PATH's address is some number
./b.out --> another number
So, what causes this difference between 2 numbers? I hope I have clearly demonstrated what I want to ask. Thanks mates.
Typically, environment variables are part of some "process data block", and those are inherited from the starting process. If you are running a program in a debugger, that debugger will have its own process data block and your program will inherit its process data block from the debugger. That in turn might have inherited the program data block of the IDE.
This doesn't matter anyway, because the interface to the environment variables doesn't give you that kind of details. For instance, on Windows it's quite likely that the environment variables will be converted from Unicode to your local 8 bit codepage when you ask for them. You'd never see the original variable, just (an approximation of) its value.
Perhaps you want to do?
printf("%s",getenv("PATH"));
Getting the environment variable string does make sense.
But, the address where the system gives you the string, has no relevance anywhere
(particularly outside the scope of this program).
You should be interested in the environment string value rather than its address.
If you have any reason to use the address, please give that here.
For example,
echo $PATH
gives me,
/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin: ... etc
All my programmatic interest with PATH would be in its contents not any sort of address.
Why would you expect it to return the same memory location every time? getenv returns "a pointer to a string containing the value for the specified name." It is not specified which memory location the string is located at, nor whether that location will later be overwritten.
I'm lead dev for Bitfighter, and we're using Lua as a scripting language to allow players to program their own custom robot ships.
In Lua, you need not declare variables, and all variables default to global scope, unless declared otherwise. This leads to some problems. Take the following snippet, for example:
loc = bot:getLoc()
items = bot:findItems(ShipType) -- Find a Ship
minDist = 999999
found = false
for indx, item in ipairs(items) do
local d = loc:distSquared(item:getLoc())
if(d < minDist) then
closestItem = item
minDist = d
end
end
if(closestItem != nil) then
firingAngle = getFiringSolution(closestItem)
end
In this snippet, if findItems() returns no candidates, then closestItem will still refer to whatever ship it found the last time around, and in the intervening time, that ship could have been killed. If the ship is killed, it no longer exists, and getFiringSolution() will fail.
Did you spot the problem? Well, neither will my users. It's subtle, but with dramatic effect.
One solution would be to require that all variables be declared, and for all variables to default to local scope. While that change would not make it impossible for programmers to refer to objects that no longer exist, it would make it more difficult to do so inadvertently.
Is there any way to tell Lua to default all vars to local scope, and/or to require that they be declared? I know some other languages (e.g. Perl) have this option available.
Thanks!
Lots of good answers here, thanks!
I've decided to go with a slightly modified version of the Lua 'strict' module. This seems to get me where I want to go, and I'll hack it a little to improve the messages and make them more appropriate for my particular context.
There is no option to set this behavior, but there is a module 'strict' provided with the standard installation, which does exactly that (by modifying the meta-tables).
Usage:
require 'strict'
For more in-depth info and other solutions: http://lua-users.org/wiki/DetectingUndefinedVariables, but I recommend 'strict'.
Sorta.
In Lua, globals notionally live in the globals table _G (the reality is a bit more complex, but from the Lua side there's no way to tell AFAIK). As with all other Lua tables, it's possible to attach a __newindex metatable to _G that controls how variables are added to it. Let this __newindex handler do whatever you want to do when someone creates a global: throw an error, permit it but print a warning, etc.
To meddle with _G, it's simplest and cleanest to use setfenv. See the documentation.
"Local by default is wrong". Please see
http://lua-users.org/wiki/LocalByDefault
http://lua-users.org/wiki/LuaScopingDiscussion
You need to use some kind of global environment protection. There are some static tools to do that (not too mature), but the most common solution is to use runtime protection, based on __index and __newindex in _G's metatable.
Shameles plug: this page may also be useful:
http://code.google.com/p/lua-alchemy/wiki/LuaGlobalEnvironmentProtection
Note that while it discusses Lua embedded into swf, the described technique (see sources) do work for generic Lua. We use something along these lines in our production code at work.
Actually, the extra global variable with the stale reference to the ship will be sufficient to keep the GC from discarding the object. So it could be detected at run time by noticing that the ship is now "dead" and refusing to do anything with it. It still isn't the right ship, but at least you don't crash.
One thing you can do is to keep user scripts in a sandbox, probably a sandbox per script. With the right manipulation of either the sandbox's environment table or its metatable, you can arrange to discard all or most global variables from the sandbox before (or just after) calling the user's code.
Cleaning up the sandbox after calls would have the advantage of discarding extra references to things that shouldn't hang around. This could be done by keeping a whitelist of fields that are allowed to remain in the environment, and deleting all the rest.
For example, the following implements a sandboxed call to a user-supplied function with an environment containing only white-listed names behind a fresh scratch table supplied for each call.
-- table of globals that will available to user scripts
local user_G = {
print=_G.print,
math=_G.math,
-- ...
}
-- metatable for user sandbox
local env_mt = { __index=user_G }
-- call the function in a sandbox with an environment in which new global
-- variables can be created and modified but they will be discarded when the
-- user code completes.
function doUserCode(user_code, ...)
local env = setmetatable({}, env_mt) -- create a fresh user environment with RO globals
setfenv(user_code, env) -- hang it on the user code
local results = {pcall(user_code, ...)}
setfenv(user_code,{})
return unpack(results)
end
This could be extended to make the global table read-only by pushing it back behind one more metatable access if you wanted.
Note that a complete sandbox solution would also consider what to do about user code that accidentally (or maliciously) executes an infinite (or merely very long) loop or other operation. General solutions for this are an occasional topic of discussion on the Lua list, but good solutions are difficult.