Thank you a lot, Thomas! This helps to understand why the code works for F.log_softmax() but not with torch.log(...). Still, I was not understanding why the backward() pass had to go through the problematic derivative in the first place. In particular, I can avoid the error by doing the following:
w = torch.tensor([1.,2.,3.], requires_grad=True)
x = torch.tensor([[1,0,1]])
c = torch.tensor([0])

p = w*x / (w*x).sum(-1)
print(p)

nll = -torch.log(p[0][0]) #target class = c = 0
print(nll)

nll.backward()

print(w.grad)

which produces the following output:
tensor([[0.2500, 0.0000, 0.7500]], grad_fn=<DivBackward0>). #p
tensor(1.3863, grad_fn=<NegBackward>) #nll_loss
tensor([-0.7500,  0.0000,  0.2500]) #  gradients

As expected, the derivative of the nll_loss (equivalent to the example above) works fine, since no -inf score is involved in its computation. Instead, if I use the following to produce the log-probabilities (and the nll_loss), I get the nan gradients.
logits = torch.log(p)
nll = -logits[0][0]
print(nll)

nll.backward()

print(w.grad)

output:
tensor([[0.2500, 0.0000, 0.7500]], grad_fn=<DivBackward0>) #p (same as before!)
tensor(1.3863, grad_fn=<NegBackward>) #nll_loss (same as before!)
tensor([nan, nan, nan]) # gradients

The only difference with the previous examples is that in this case I build the computational graph for the useless (and problematic) case, which comes from torch.log(logits[0][1]). Even if I don’t care about this value in the nll_loss computation, it seems its backward graph is still processed when I do  F.nll_loss(torch.log(p), [0]).backward().
Thank you again.